Войти
ПрограммированиеФорум2D графика и изометрия

Как подойти к задаче "прямоугольник со скругленными углами" на GLSL?

Страницы: 1 2 Следующая »
#0
14:11, 26 апр. 2019

Мой текущий шейдер

/************************************** roundedCorners.frag **************************************/
#ifdef GL_ES
precision highp float;
#endif

uniform sampler2D texture;
uniform vec2 radius;

varying vec4 vColor;
varying vec2 vTexCoord;

bool outOfRadius(vec2 corner) {
    return pow(corner.x - vTexCoord.x, 2.0) / pow(radius.x, 2.0) + pow(corner.y - vTexCoord.y, 2.0) / pow(radius.y, 2.0) > 1.0;
}

bool isTransparent() {
    vec2 leftTop = vec2(radius.x, radius.y);
    vec2 rightTop = vec2(1.0 - radius.x, radius.y);
    vec2 rightBottom = vec2(1.0 - radius.x, 1.0 - radius.y);
    vec2 leftBottom = vec2(radius.x, 1.0 - radius.y);
    return
    (vTexCoord.x < leftTop.x && vTexCoord.y < leftTop.y && outOfRadius(leftTop)) ||
    (vTexCoord.x > rightTop.x && vTexCoord.y < rightTop.y && outOfRadius(rightTop)) ||
    (vTexCoord.x > rightBottom.x && vTexCoord.y > rightBottom.y && outOfRadius(rightBottom)) ||
    (vTexCoord.x < leftBottom.x && vTexCoord.y > leftBottom.y && outOfRadius(leftBottom));
}

void main() {
    vec4 texColor = texture2D(texture, vTexCoord);
    if (radius.x != 0.0 && radius.y != 0.0 && isTransparent()) {
        gl_FragColor = vec4(0, 0, 0, 0);
    } else {
        gl_FragColor = vColor * texColor;
    }
}

/************************************** roundedCorners.vert **************************************/
#ifdef GL_ES
precision highp float;
#endif

uniform mat4 projectionViewMatrix;

attribute vec2 Position;
attribute vec4 Color;
attribute vec2 TexCoord;

varying vec4 vColor;
varying vec2 vTexCoord;

void main() {
    vColor = Color;
    vTexCoord = TexCoord;
    gl_Position = projectionViewMatrix * vec4(Position.xy, 0.0, 1.0);
}

Проблема в том, что такому простому скруглению не хватает гладкости

Прямоугольник со скругленными углами | Как подойти к задаче "прямоугольник со скругленными углами" на GLSL?

Вопрос: как люди, которые умеют в графике программируют такие вещи?


#1
15:46, 26 апр. 2019

https://stackoverflow.com/questions/43970170/bordered-rounded-rectangle-in-glsl
http://qaru.site/questions/12428163/glsl-2d-rounded-corners

#2
(Правка: 28 апр. 2019, 7:16) 20:07, 26 апр. 2019

lookid
Самое подходящее решение в терминах GLSL отсюда http://qaru.site/questions/12428163/glsl-2d-rounded-corners

#ifdef GL_ES
precision highp float;
#endif

uniform vec2 resolution;
uniform vec2 offset;

varying vec2 vPosition;
varying vec4 vColor;

void main()
{
    float vignetteMax = pow(0.2, 4.0);
    vec2 pos = (gl_FragCoord.xy - offset) / resolution;
    float vignette = pos.x * pos.y * (1. - pos.x) * (1. - pos.y);
    vec4 color = vColor;
    color.rgba = color.rgba * smoothstep(0.0, vignetteMax, vignette);
    gl_FragColor = color;
}

Все равно выдает слишком явный градиент по углам (на изображении на обводку можно не обращать внимания)

Как подойти к задаче "прямоугольник со скругленными углами" на GLSL? | Как подойти к задаче "прямоугольник со скругленными углами" на GLSL?

Может быть, как-то понакладывать маску PNG файлом? Или шейдер можно довести до ума?

#3
20:23, 26 апр. 2019

https://www.shadertoy.com/view/WlXGDN

#4
21:14, 26 апр. 2019

featurea
1. Пишем функцию которая возвращает дистанцию до прямоугольника без скруглений

float dist_Rect(vec2 pixel, vec2 rect_center, vec2 rect_size) {  
  vec2 d = abs(rect_center - pixel) - rect_size*0.5;
  return length(max(d,0.0));
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    float d = dist_Rect(fragCoord.xy, vec2(200, 250), vec2(260, 160));
    if (d <= 0.0) 
        fragColor = vec4(1, 0, 0, 1);
    else
        fragColor = vec4(0, 0, 0, 1);
}
2. Делаем скругления вычитая из этой дистанции радиус скругления (не забываем прямоугольник уменьшить при этом):
float dist_RoundRect(vec2 pixel, vec2 rect_center, vec2 rect_size, float rect_round) {
    return dist_Rect(pixel, rect_center, rect_size - vec2(rect_round*2.0)) - rect_round;
}
https://www.shadertoy.com/view/WtX3DN
#5
(Правка: 22:01) 21:55, 26 апр. 2019

Это очень лаконичный код, но он не выдает сглаживание. Углы будут лесенкой.

Вот скриншот под 6x увеличением для `rect_size = vec2(300.0, 300.0)` и `rect_round = 10.0`

Как подойти к задаче "прямоугольник со скругленными углами" на GLSL? | Как подойти к задаче "прямоугольник со скругленными углами" на GLSL?

Или я чего-то не того (много) хочу? Можно как-то альфа канал подрихтовать?

#6
(Правка: 27 апр. 2019, 0:12) 23:41, 26 апр. 2019

featurea
> Или я чего-то не того (много) хочу? Можно как-то альфа канал подрихтовать?
В d у тебя дистанция. Ты можешь сделать плавный переход между красным и черным с помощью этого d. Например так: fragColor = mix(vec4(1, 0, 0, 1), vec4(0, 0, 0, 1), clamp(d+0.5,0.0,1.0)); (обновил ссылку на шейдертой)

#7
0:07, 27 апр. 2019

Я немного переделал вариант от MrShoor.
Выглядит нормально, а лесенка она при увеличение всегда будет, вопрос в том, как сильно увеличить ))
мой вариант

float dist_Rect(vec2 pixel, vec2 rect_center, vec2 rect_size) 
{  
  vec2 d = abs(rect_center - pixel) - rect_size*0.5;
  return length(max(d,0.0));
}

float dist_RoundRect(vec2 pixel, vec2 rect_center, vec2 rect_size, float rect_round) 
{
    return dist_Rect(pixel, rect_center, rect_size - vec2(rect_round*2.0)) - rect_round;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    float d = dist_RoundRect(fragCoord.xy, iResolution.xy * 0.5, vec2(iResolution.xy - 10.0), 30.0);
    fragColor = mix(vec4(1, 0, 0, 1), vec4(0, 0, 0, 1), clamp(d-0.5,0.0,1.0));
}

#8
(Правка: 23:46) 11:07, 27 апр. 2019

stratego
> Выглядит нормально
Меня тоже устроило. Теперь пробую добавить к коду MrShoor текстуру (надо по задаче)

+ Показать
void main()
{
    vec4 textureColor = texture2D(texture, vTexCoord) * vColor;
    float d = dist_RoundRect(gl_FragCoord.xy, origin, size, radius);
    gl_FragColor = mix(vec4(1, 1, 1, 1), vec4(0.6, 0.6, 0.6, 0), clamp(d-0.5,0.0,1.0)) * textureColor;
}

Текстурой беру фиолетовый прямоугольник 100x100

Как подойти к задаче "прямоугольник со скругленными углами" на GLSL? | Как подойти к задаче "прямоугольник со скругленными углами" на GLSL?

При `rect_size=vec2(400, 400)` и `rect_round=80` на общей картинке глазу кажется, что в левом верхнем углу резкий переход

Как подойти к задаче "прямоугольник со скругленными углами" на GLSL? | Как подойти к задаче "прямоугольник со скругленными углами" на GLSL?

Но ведь по пикселям все углы идентичны

+ Показать

Прихожу к тому, что дело в `clamp(d-0.5,0.0,1.0)`. Меняю на `clamp(d+1.0,0.0,1.0)` и получаю что-то красивое с обводкой по левому и верхнему краю

Как подойти к задаче "прямоугольник со скругленными углами" на GLSL? | Как подойти к задаче "прямоугольник со скругленными углами" на GLSL?

Переворачиваю этот же (то есть предыдущий) скриншот на 90 градусов в пейнте - все равно для глаза обводка по левому и верхнему краю

Как подойти к задаче "прямоугольник со скругленными углами" на GLSL? | Как подойти к задаче "прямоугольник со скругленными углами" на GLSL?

То есть дело не в шейдере или в шейдере?

#9
(Правка: 23:15) 21:25, 27 апр. 2019

ещё есть такой вариант:

#define BASE 4.0
float f(float v){return pow(abs(v),BASE);}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 pos = fragCoord.xy-iResolution.xy*0.5;///iResolution.yy;
    pos=pos*(2.0/iResolution.y);
    float m = f(pos.x) + f(pos.y);
    float k=1.0-pow(abs(m),32.0);
    vec4 color = vec4(1, 0.85, 0, 1) * k;
    fragColor = color;
}
https://www.shadertoy.com/view/wtl3D4
x4_plus_y4 | Как подойти к задаче "прямоугольник со скругленными углами" на GLSL?

upd:
заменил pow(...,...) на pow(abs(...),...)

#10
(Правка: 28 апр. 2019, 3:39) 22:55, 27 апр. 2019

Adler
Я немного упростил код, чтобы читалось и ввел две переменные для центра прямоугольника `vec2 center` и его размера `vec2 size` https://www.shadertoy.com/view/tlsGWN

float pow4(float value) { return pow(value, 4.0); }

float pow16(float value) { return pow(value, 16.0); }

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 center = vec2(200, 200);
    vec2 size = vec2(100, 100);
    vec2 pos = 2.0 * (fragCoord.xy - center) / size;
    fragColor = vec4(1.0 - pow16(pow4(pos.x) + pow4(pos.y)), 0, 0, 0);
}
Как подойти к задаче "прямоугольник со скругленными углами" на GLSL? | Как подойти к задаче "прямоугольник со скругленными углами" на GLSL?

Выглядит отлично. У меня даже не вопрос как оно работает, а вопрос, как бы тут в коде третьей переменной за-exctract-ить радиус скругления `float radius`?

#11
(Правка: 23:21) 23:20, 27 апр. 2019

featurea
> за-exctract-ить радиус скругления
BASE как-то связан с радиусом. Чем больше BASE тем сильнее похоже на квадрат.

#12
(Правка: 28 апр. 2019, 7:16) 23:23, 27 апр. 2019

Adler
Вывел переменную `float radius` https://www.shadertoy.com/view/tlsGWN

#define center       vec2(200, 200)
#define size         vec2(200, 200)
#define radius       20.0

float roundedRectangle(vec2 fragCoord)
{   
    vec2 pixel = fragCoord.xy - center;
    vec2 uv = pixel / (0.5 * size);                           // (u, v) = (-1..1, -1..1)
    vec2 angularity = size / radius;                          // n = 0..Infinity
    return pow(uv.x, angularity.x) + pow(uv.y, angularity.y); // u^n + v^n = 0..1 - это основная магия, дальше подгон полученного под желаемое
}

float invertIntence(float value /*0..1*/)
{
    float intenseValue = pow(value, 32.0);
    float invertedIntenseValue = 1.0 - intenseValue;
    return invertedIntenseValue;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{   
    float darkness = roundedRectangle(fragCoord);
    float brightness = invertIntence(darkness);
    fragColor = vec4(1, 0.85, 0, 0) * brightness;
}
Как подойти к задаче "прямоугольник со скругленными углами" на GLSL? | Как подойти к задаче "прямоугольник со скругленными углами" на GLSL?

Что можно про это сказать? Что операция возведения в степень дорогая? Или что-то еще?

#13
1:40, 28 апр. 2019

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

#14
(Правка: 3:51) 3:38, 28 апр. 2019

Daniil Petrov
> постсглаживание
какой это вызов  GL API для самых одаренных? :)

И еще у меня вопрос. Как GLSL считает pow(-1, 0.5)? Это же NAN?

Страницы: 1 2 Следующая »
ПрограммированиеФорум2D графика и изометрия