Как воспроизвести эффект рамки Photoshop Bevel / Emboss в glsl

Я пытался найти информацию о том, как можно воспроизвести эффект скоса фотошопа с помощью шейдера GLSL.

Пример эффекта в PS

Я нашел несколько примеров шейдеров, но не могу осмыслить это. Я наткнулся на этот вопрос https://dsp.stackexchange.com/questions/530/bitmap-alpha-bevel-algorithm, который дает желаемый результат, но я не знаю, как преобразовать его в шейдер.

Любой совет будет принят во внимание.


person DUDSS    schedule 18.11.2018    source источник


Ответы (1)


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

Я бы разделил эту проблему на две отдельные:

    1. Find distance and direction to the closest hole.
    1. Shade pixel based on distance/direction.

Объявление. 1.

Вы хотите найти ближайший пиксель, у которого альфа-канал ниже некоторого порога. Вы тестируете пиксель, с которого начинается ваш шейдер, затем вы тестируете его соседей (сетка 3x3 без центра), затем их соседей (5x5) и так далее ... Вы продолжаете это, пока не найдете пиксель или не превысите размер ваш скос.

Это сложная часть. Здесь не так много математики, но у вас есть ОЧЕНЬ много считываний текстур и if-else которые не нравятся графическим процессорам. Когда вы увеличиваете размер границы, производительность падает очень быстро. Кажется, что у графических процессоров есть какая-то функция «тайм-аута» при выполнении шейдеров, поэтому даже идеально работающий может быть тихо убит, если это займет слишком много времени. Эти ограничения могут различаться между графическими процессорами и / или драйверами, поэтому трудно сказать, будет ли код, работающий на вашем компьютере, работать на другом. Это сложно проверить с уверенностью, но можно.

Объявление. 2.

С расстоянием и направлением вы почти закончили. Если расстояние больше, чем размер границы, то текущий пиксель не является границей, в противном случае вы сравниваете свое направление с некоторым светлым направлением (в вашем примере оно было вверх-влево) и решаете, должна ли граница быть светлее или темнее. Вы также можете использовать расстояние, чтобы влиять на силу света / темноты, чтобы вы могли получить округлые склоны вместо плоских.

Все это простейший подход. Вы можете попытаться разделить его на проходы рендеринга, выполнить некоторые предварительные вычисления, уменьшить текстуры, использовать MIP-карты в качестве четырехугольных деревьев и т. Д., Чтобы ускорить код.

ИЗМЕНИТЬ Для вашего комментария:

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

Допустим, у вас есть текстура, в которой дырки белые, а остальные черные, и вы хотите смягчить это изображение. Вы пишете шейдер, который выбирает текущий пиксель (назовем его pix), выбирает его 8 соседей и усредняет их (назовем его avg), затем вы вызываете:

result = max( pix, avg );

Таким образом вы размазываете белый цвет вокруг, но никогда не затемняете уже белые пиксели. Вы запускаете этот шейдер несколько раз подряд, чтобы получить больший мазок. Теперь, если вы инвертируете цвета, вы получите что-то вроде значений расстояния, верно :)?

(Это можно сделать без инверсии, вы используете alpha канал и min вместо max, я просто почувствовал, что этот способ проще описать).

Форма этого мазка будет зависеть от образца ваших образцов для значения avg. Я сказал вам взять сетку 3x3, но вы можете поэкспериментировать и использовать более круглые формы.

Градиент этого значения расстояния даст вам направление.

Вы можете пойти еще дальше и предварительно вычислить данные затенения. Вы можете вычислить текстуру со значениями, которые нужно добавить или вычесть для каждого пикселя. Упакуйте эту текстуру в диапазон от 0 до 255. Затем во время рендеринга вы берете образец этой текстуры, вычитаете из нее 0,5 (для перехода в диапазон [-0,5,0,5]) и добавляете к исходной текстуре.

person kolenda    schedule 27.11.2018
comment
Спасибо за ответ. На данный момент я просто использовал отдельные текстуры с примененным эффектом тиснения PS и визуализировал их с помощью шейдера по умолчанию. Но, скажем, я использовал предложенный вами подход. Вы указываете, что производительность может быть проблемой (давайте проигнорируем проблему тайм-аута / машины). Считаете ли вы, что рендеринг набора текстур с использованием шейдера в закадровый буфер только один раз, а затем повторное использование этого буфера, является жизнеспособным вариантом? (Предполагая, что визуализированный буфер не меняется). Или лучше просто сделать это на процессоре с обычным программированием? - person DUDSS; 27.11.2018