我正在尝试用GLSL编写一个函数,将带符号的距离返回给一个矩形。矩形是轴对齐的。我觉得有点卡住了;我只是不知道我需要做什么来使它工作。
我想出的最好的办法是:
float sdAxisAlignedRect(vec2 uv, vec2 tl, vec2 br)
{
// signed distances for x and y. these work fine.
float dx = max(tl.x - uv.x, uv.x - br.x);
float dy = max(tl.y - uv.y, uv.y - br.y);
dx = max(0.,dx);
dy = max(0.,dy);
return sqrt(dx*dx+dy*dy);
}
它产生一个矩形,看起来像:
线条显示与矩形的距离。它可以正常工作,但仅适用于矩形之外的距离。矩形内部的距离是静态0.
。
如何使用统一公式获得矩形内的精确距离?
这个怎么样…
float sdAxisAlignedRect(vec2 uv, vec2 tl, vec2 br)
{
vec2 d = max(tl-uv, uv-br);
return length(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y));
}
这是结果,其中绿色标记为正距离,红色标记为负距离(代码如下):
分解:
>
获取x和y边框的带符号距离。u-左
和右-u
是两个x轴距离。取这些值中的最大值给出到最近边框的带符号距离。查看d. x
和d.y
分别显示在下图中。
组合x和y:
>
如果两个值都是负数,则取最大值(即最接近边框)。这是通过min(0.0, max(d.x,d.y))
完成的。
如果只有一个值是正的,那就是我们想要的距离。
如果两个值都是正数,则最近的点是一个角,在这种情况下,我们想要长度。这可以与上述情况结合使用,无论如何都取长度并确保两个值都是正数:长度(max(vec2(0.0), d)
。
这两部分对方程是互斥的,即只有一部分会产生非零值,并且可以求和。
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord.xy / iResolution.xy;
uv -= 0.5;
uv *= vec2(iResolution.x/iResolution.y,1.0);
uv += 0.5;
float d = sdAxisAlignedRect(uv, vec2(0.3), vec2(0.7));
float m = 1.0 - abs(d)/0.1;
float s = sin(d*400.0) * 0.5 + 0.5;
fragColor = vec4(s*m*(-sign(d)*0.5+0.5),s*m*(sign(d)*0.5+0.5),0,1);
}