GLSL圆角矩形角被拉伸

时间:2019-09-30 13:41:18

标签: opengl glsl rounded-corners

我正在用openGL编程GUI库,并决定添加圆角,因为我觉得它给单元带来了更专业的外观。 我已经实现了通用

length(max(abs(p) - b, 0.0)) - radius

该方法几乎可以完美地起作用,除了在角落处好像它们被拉伸一样。

enter image description here

我的片段着色器:

in vec2 passTexCoords;

uniform vec4 color;
uniform int width;
uniform int height;
uniform int radius;    

void main() {
    fragment = color;

    vec2 pos = (abs(passTexCoords - 0.5) + 0.5) * vec2(width, height);

    float alpha = 1.0 - clamp(length(max(pos - (vec2(width, height) - radius), 0.0)) - radius, 0.0, 1.0);

    fragment.a = alpha;
}

拉伸对我来说确实有意义,但是当我替换为

vec2 pos = (abs(passTexCoords - 0.5) + 0.5) * vec2(width, height) * vec2(scaleX, scaleY);

float alpha = 1.0 - clamp(length(max(pos - (vec2(width, height) * vec2(scaleX, scaleY) - radius), 0.0)) - radius, 0.0, 1.0);

(其中scaleX和scaleY是介于0.0和1.0之间的标量,代表矩形相对于屏幕的宽度和高度),该矩形几乎完全消失了:

enter image description here

2 个答案:

答案 0 :(得分:0)

我假设passTexCoords是[0,1]范围内的纹理坐标。 widthheight就是屏幕的大小。 scaleXscaleY是绿色区域与屏幕尺寸的比率。
以像素为单位计算当前片段相对于绿色区域中心的绝对位置(pos):

vec2 pos = (abs(passTexCoords - 0.5) + 0.5) * vec2(width*scaleX, height*scaleY);

计算从圆弧的中心点到当前片段的距离:

vec2 arc_cpt_vec = max(pos - vec2(width*scaleX, height*scaleY) + radius, 0.0);

如果向量的长度大于半径,则必须跳过片段:

float alpha = length(arc_cpt_vec) > radius ? 0.0 : 1.0;

答案 1 :(得分:0)

问题在于,距离没有按比例缩放到屏幕空间中,因此结果是沿最大窗口轴拉伸。如果将标准化位置乘以屏幕的长宽比以及框的其他参数,则可以解决此问题。我在Shadertoy上写了一个这样做的例子:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Input info
    vec2 boxPos; // The position of the center of the box (in normalized coordinates)
    vec2 boxBnd; // The half-bounds (radii) of the box (in normalzied coordinates)
    float radius;// Radius


    boxPos = vec2(0.5, 0.5);    // center of the screen
    boxBnd = vec2(0.25, 0.25);  // half of the area
    radius = 0.1;

    // Normalize the pixel coordinates (this is "passTexCoords" in your case)
    vec2 uv = fragCoord/iResolution.xy;

    // (Note: iResolution.xy holds the x and y dimensions of the window in pixels)
    vec2 aspectRatio = vec2(iResolution.x/iResolution.y, 1.0);

    // In order to make sure visual distances are preserved, we multiply everything by aspectRatio
    uv *= aspectRatio;
    boxPos *= aspectRatio;
    boxBnd *= aspectRatio;

    // Time varying pixel color
    vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));

    // Output to screen
    float alpha = length(max(abs(uv - boxPos) - boxBnd, 0.0)) - radius;

    // Shadertoy doesn't have an alpha in this case
    if(alpha <= 0.0){
        fragColor = vec4(col,1.0);
    }else{
        fragColor = vec4(0.0, 0.0, 0.0, 1.0);
    }
}

执行此操作可能会花费较少的计算成本,但这是我准备的一个简单解决方案。