GLSL Shader: сопоставление баров в полярных координатах

Я хочу создать полярное представление этого шейдера: https://www.shadertoy.com/view/4sfSDN

Чтобы это выглядело как на этом скриншоте: http://postimg.org/image/uwc34jxxz/

Я знаю основы полярной системы: как рассчитать r и ϕ, но я могу использовать эти значения только с функцией загрузки texture2d() на изображении.

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

r должен каким-то образом основываться на амплитуде, но тогда я не знаю, как нарисовать круг без функции texture2d()... я могу нарисовать круг только с r, но тогда нет разных амплитуд. Или мне даже нужно заполнить матрицу сгенерированными полосами в цикле и загрузить круг оттуда?

Я совершенно уверен, что это возможно, из-за безумных шейдеров на шейдертое, но я не совсем понимаю... Может ли кто-нибудь указать мне решение?


person Inko Gnito    schedule 01.09.2015    source источник


Ответы (1)


Из опубликованного вами шейдера я думаю, что должно быть достаточно просто преобразовать uv в полярные координаты.

Итак, что вы ищете, это угол и радиус от центра. Сначала давайте преобразуем uv, чтобы он давал вектор, указывающий из центра:

uv = fragCoord - (iResolution*.5);

Затем попытайтесь нормализовать его. Поскольку вид не квадратный, преобразование нормализации должно быть только по 1 координате, так что

if(iResolution.x>iResolution.y)
{
   uv = uv/iResolution.y;
}
else
{
   uv = uv/iResolution.x;
}

Это создаст эффект подгонки, но вы можете просто жестко запрограммировать одно или другое, если вам нужно. min можно использовать, если доступно (uv = uv/min(iResolution.x, iResolution.y))), чтобы удалить условие.

Таким образом, в этой точке вектор uv указывает от центра к положению пикселя в системе координат, нормализованной в одном измерении.

Теперь, чтобы получить угол, вы можете просто использовать atan(uv.y, uv.x). Чтобы получить радиус, вам нужно length(uv).

Радиус в вашем случае будет для более короткого размера в диапазоне [0, .5], поэтому вы можете умножить его на 2,0, но это фактор, который вы можете позже изменить, чтобы получить желаемый эффект, чтобы максимальное значение не достигало границы но, может быть, 80% или около того (просто поиграйте с этим).

Угол находится в диапазоне [-Pi, Pi], плюс в документах говорится, что он не работает для X = 0, с которым вам нужно будет справиться самостоятельно. Итак, теперь угол должен быть преобразован в диапазон [.0, 1.0], чтобы получить доступ к координате текстуры:

angle = angle/(Pi*2.0) + .5

Итак, теперь создайте новый uv

uv = vec2(angle, radius)

И используйте тот же шейдер, что и раньше.

Вы также должны иметь в виду, что радиус может быть больше 1,0 в углах, что может привести к неправильному доступу к текстуре. В таких случаях лучше всего отказаться от фрагмента.

Из шейдерной игрушки:

#define M_PI 3.1415926535897932384626433832795

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy - (iResolution.xy*.5);
    uv = uv/min(iResolution.x, iResolution.y);
    float angle = atan(uv.y, uv.x);
    angle = angle/(M_PI*2.0) + .5;
    float radius = length(uv);
    uv = vec2(angle, radius*2.0);

    float bars = 24.;
    float fft  = texture2D( iChannel0, vec2(floor(uv.x*bars)/bars,0.25) ).x;
    float amp = (fft - uv.y)*100.;
    fragColor = vec4(amp,0.,0.,1.0);
}
person Matic Oblak    schedule 02.09.2015
comment
большое спасибо, это помогло! красивый! но мне пришлось использовать угол = угол / (Pi * 2,0) + 0,5 (не 1,0), чтобы сопоставить значение угла с [0,0-1,0]... это правильно? Я проверил значения с помощью jfiddle:ссылка - person Inko Gnito; 03.09.2015
comment
Да вы правы. Я сделал ошибку, когда писал это из головы. Позвольте мне исправить это.. - person Matic Oblak; 03.09.2015
comment
Перед строкой цвета фрага добавьте if(ceil(uv.xbars)-uv.xbars ‹ .1) amp = .0; - person Matic Oblak; 03.09.2015