2015-05-30 4 views
10

Я пытаюсь написать функцию в 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); 
} 

Который производит прямоугольник, который выглядит как:

enter image description here

Линии показывают расстояние от прямоугольника. Он отлично работает, но ТОЛЬКО для расстояний вне прямоугольника. Внутри прямоугольника расстояние статическое 0..

Как получить точные расстояния внутри прямоугольника, используя единую формулу?

ответ

13

Как об этом ...

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)); 
} 

Вот result, где зеленые метки положительное расстояние и красный отрицательный (код ниже):

enter image description here


Разбивка:

  1. Получите подписанное расстояние от границ x и y. u - left и right - u - это два расстояния по оси x. Принимая максимум этих значений, вы получаете знаковое расстояние до ближайшей границы. Просмотр изображений d.x и d.y показаны на рисунках ниже.

  2. Объединить й и у:

    1. Если оба значения отрицательны, взять максимум (т.е. ближе к границе). Это делается с помощью min(0.0, max(d.x, d.y)).

    2. Если только одно значение положительное, это то расстояние, которое мы хотим.

    3. Если оба значения положительны, ближайшая точка является углом, и в этом случае мы хотим длину. Это можно комбинировать с приведенным выше случаем, принимая длину в любом случае и убедившись, что оба значения положительны: length(max(vec2(0.0), d)).

    Эти две части уравнения являются взаимоисключающими, то есть только один будет производить ненулевое значение и может быть суммирован.

enter image description hereenter image description here


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); 
} 
+0

Отлично! Отличная работа. – tenfour

+0

@jozxyqk Как вы придумали эту функцию? –

+0

@ v.shashenko проб и ошибок действительно. Я обновил ответ, чтобы перейти к более подробному описанию. – jozxyqk

Смежные вопросы