Прямоугольные углы GLSL вытянуты - PullRequest
1 голос
/ 30 сентября 2019

Я программирую библиотеку графического интерфейса в openGL и решил добавить закругленные углы, потому что я чувствую, что это дает гораздо более профессиональный вид подразделениям. Я реализовал общий метод

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 голосов
/ 30 сентября 2019

Проблема заключается в том, что расстояния не масштабируются в экранном пространстве и поэтому растягиваются по наибольшей оси окна. Это можно исправить, если умножить нормализованное положение на соотношение сторон экрана вместе с другими параметрами для поля. Я написал пример для 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);
    }
}

Может быть менее затратный способ сделать это, но это было простое решение, которое я приготовил.

0 голосов
/ 30 сентября 2019

Я предполагаю, что passTexCoords - это координата текстуры в диапазоне [0, 1]. И что width и height это размер экрана. И scaleX и scaleY - это отношение зеленой области к размеру экрана.
Вычисление абсолютной позиции (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;
...