Во-первых, я предупреждаю вас, что это может быть сложно вписать в шейдер, в зависимости от вашего графического процессора и желаемого качества, но вы можете попробовать.
Я бы разделил эту проблему на две отдельные:
- Find distance and direction to the closest hole.
- 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