Как скопировать эффект скоса / тиснения в фотошопе в glsl - PullRequest
0 голосов
/ 18 ноября 2018

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

Example of the effect in PS

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

Любой совет будет оценен.

1 Ответ

0 голосов
/ 27 ноября 2018

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

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

    1. Найти расстояние и направление до ближайшего отверстия.
    1. Пиксельный оттенок в зависимости от расстояния / направления.

Ad. 1.

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

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

Ad. 2.

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

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

РЕДАКТИРОВАТЬ Для вашего комментария:

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

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

result = max( pix, avg );

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

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

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

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

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

...