Я хотел бы загружать произвольные сетки и рисовать толстые черные линии по краям, чтобы они выглядели как тени. Мне удалось нарисовать черный силуэт вокруг объектов с помощью буфера трафарета. Вы можете увидеть результат здесь:
Но чего не хватает, так это черных линий в самом объекте. Я думал о проверке нормальных разрывов: Проверка, имеет ли соседний пиксель вектор нормали, отличный от текущего. Если да, то грань найдена. К сожалению, я понятия не имею, как я мог бы реализовать этот подход, ни в OpenGL, ни в вершинном / фрагментном шейдере GLSL.
Я был бы очень рад за некоторую помощь относительно этого подхода или любого другого относительно обнаружения края.
Изменить: я не использую никаких текстур для моей сетки.
Точнее, я хотел бы создать решение CAD / CAM, которое будет выглядеть как можно больше (взято из Top Solid https://www.youtube.com/watch?v=-qTJZtYUDB4 ):
источник
Ответы:
Обычно обнаружение краев сводится к обнаружению областей изображения с высоким значением градиента.
В нашем случае мы можем грубо рассматривать градиент как производную функции изображения, поэтому величина градиента дает вам информацию о том, насколько ваше изображение изменяется локально (в отношении соседних пикселей / текселей).
Теперь, как вы говорите, ребро является признаком разрыва, так что теперь, когда мы определили градиент, стало ясно, что эта информация - все, что нам нужно. Как только мы находим градиент изображения, нужно просто применить к нему порог, чтобы получить двоичное значение ребро / не ребро.
Как вы нашли этот градиент действительно то, что вы спрашиваете, и я еще не ответил :)
Много способов! Здесь пара :)
Встроенные шейдерные функции
И hlsl, и glsl предлагают производные функции. В GLSL у вас есть dFdx и dFdy, которые дают вам соответственно информацию о градиенте в направлении x и y. Обычно эти функции оцениваются в блоке из фрагментов 2х2.
Если вас не интересует одно направление, хороший способ получить компактный результат, который показывает, насколько сильный градиент в области, - это ширина, которая не дает вам ничего, кроме суммы абсолютных значений dFdy и dFdy.
Скорее всего, вам будет интересен край изображения в целом, а не конкретного канала, поэтому вы можете захотеть преобразовать функцию изображения в яркость. Имея это в виду, когда дело доходит до обнаружения краев, ваш шейдер может включать что-то вроде:
С высоким порогом вы найдете более грубые края, и вы можете пропустить некоторые, наоборот, с низким порогом вы можете обнаружить ложные края. Вы должны экспериментировать, чтобы найти порог, который лучше соответствует вашим потребностям.
Стоит упомянуть причину, по которой эти функции работают, но сейчас у меня нет на это времени, я, скорее всего, обновлю этот ответ позже :)
Постобработка пространства экрана
Вы могли бы пойти дальше, чем это, теперь область обнаружения краев в обработке изображений огромна. Я мог бы привести вам десятки хороших способов обнаружения краев в соответствии с вашими потребностями, но давайте пока оставим это простым, если вам интересно, я могу привести вам больше вариантов!
Таким образом, идея будет аналогична приведенной выше, с той разницей, что вы можете посмотреть на более широкую окрестность и использовать набор весов для окружающих выборок, если хотите. Как правило, вы запускаете свертку над своим изображением с ядром, которое в результате дает вам хорошую информацию о градиенте.
Очень распространенным выбором является ядро Собеля
Что соответственно дает вам градиенты в направлениях х и у:
Тогда вы можете порог, как я упоминал выше.
Это ядро, как вы можете видеть, придает больший вес центральному пикселю, поэтому эффективно вычисляет градиент + немного сглаживания, что традиционно помогает (часто изображение размыто по Гауссу для устранения маленьких краев).
Вышеописанное работает довольно хорошо, но если вам не нравится сглаживание, вы можете использовать ядра Prewitt:
(Обратите внимание, я спешу, скоро напишу правильный форматированный текст вместо изображений!)
На самом деле существует гораздо больше ядер и методов для обнаружения краев в процессе обработки изображений, а не в графике в реальном времени, поэтому я исключил более запутанные (каламбурные) методы, так как, вероятно, вам будет хорошо с функциями dFdx / y ,
источник
На всякий случай, если кому-либо еще также необходимо определить края: вот хорошая статья о том, как отображать каркас, и в этой статье объясняется, как отображать только края.
источник