OpenGL - Виявлення ребер


12

Я хотів би завантажити довільні сітки та намалювати товсті чорні лінії по краях, щоб отримати затінення тонів, як вигляд. Мені вдалося намалювати чорний силует навколо предметів, використовуючи буфер трафарету. Ви можете побачити результат тут:

введіть тут опис зображення

Але чого не вистачає - це чорні лінії в самому об’єкті. Я подумав про перевірку нормальних розривів: перевірка того, чи має сусідній піксель нормальний вектор, ніж поточний. Якщо так, то край знайдено. На жаль, я не знаю, як я міг би реалізувати цей підхід, ні в OpenGL, ні в шейдері вершин / фрагментів GLSL.

Буду дуже радий отримати допомогу щодо такого підходу чи будь-яку іншу щодо виявлення межі.

Редагувати: я не використовую жодної текстури для своїх сіток.

Занадто точніше, я хотів би створити CAD / CAM рішення, яке виглядає максимально схожим на це (взято з Top Solid https://www.youtube.com/watch?v=-qTJZtYUDB4 ):

введіть тут опис зображення


Я вважаю, що вам потрібно детальніше визначити "край". Чим він відрізняється від простого каркаса? У відповіді cifz є хороший опис простору екрану після обробки, але з вашого питання важко визначити, чи він застосовний.
Андреас

Ну, під краєм я маю на увазі "складки" та "хребти", які утворюють тверді тіла. Каркас відображатиме всі грані трикутника, а це не те, що я хочу.
enne87

Гаразд, саме те, про що я попросив :-) Я б створив каркас із цих складок та хребтів. Хитра частина все ще полягає у визначенні, що таке складка / гребінь. Чи маєте ви якесь уявлення, як це зробити?
Андреас

1
Програми cad не роблять цього в основному за допомогою шейдера. Натомість вони знають жорсткі краї в моделі та малюють лінію поверх сітчастої форми, яка містить цю інформацію.
joojaa

joojaa У вас є більше інформації про цю техніку? Що робиться у випадку подвійних вигнутих поверхонь вільної форми? Я також не впевнений, що станеться, коли у вас є конус або циліндр, який ріжуть / обробляють чимось вільною формою. stackoverflow.com/questions/43795262/…
Душан Босняк 'pailhead'

Відповіді:


18

Зазвичай виявлення країв зводиться до виявлення областей зображення з високим значенням градієнта.

У нашому випадку ми можемо грубо бачити градієнт як похідну від функції зображення, тому величина градієнта дає вам інформацію про те, наскільки ваше зображення змінюється локально (щодо сусідніх пікселів / текселів).
Тепер, край, як ви говорите, свідчить про переривання, тож тепер, коли ми визначили градієнт, зрозуміло, що ця інформація - це все, що нам потрібно. Як тільки ми знайдемо градієнт зображення, це лише питання застосування порогу до нього, щоб отримати бінарне значення край / не-край.

Як ти вважаєш цей градієнт - це справді те, про що ти питаєш, і я ще відповім :)

Багато способів! Ось пара :)

Вбудовані функції шейдера

І hlsl, і glsl пропонують похідні функції. У GLSL у вас є dFdx та dFdy, які дають відповідно інформацію про градієнт у напрямку x та y. Зазвичай ці функції оцінюються в блоці з 2x2 фрагментів.
Якщо ви не зацікавлені в одному напрямку, хороший спосіб отримати компактний результат, який вказує, наскільки сильним є градієнт у регіоні, є ширина, яка не дає нічого іншого, крім суми абсолютного значення dFdy та dFdy.
Вас, швидше за все, цікавить крає зображення в цілому, а не певний канал, тому ви можете перетворити функцію зображення на луму. Зважаючи на це, коли мова йде про виявлення краю, ваш шейдер може включати щось подібне:

  float luminance = dot(yourFinalColour,vec3(0.2126, 0.7152, 0.0722));
  float gradient = fwidth(luminance );
  float isEdge = gradient > threshold;

З високим порогом ви знайдете більш грубі краї, і ви можете пропустити деякі, навпаки, з низьким порогом ви можете виявити помилкові ребра. Ви повинні експериментувати, щоб знайти поріг, який найкраще відповідає вашим потребам.

Причину, по якій ці функції працюють, варто зазначити, але я не маю часу на це зараз, я, ймовірно, оновлюю цю відповідь пізніше :)

Пост-процес на екрані

Ви могли бути фантастичнішим за це, зараз поле виявлення країв в обробці зображень величезне. Я можу навести вам десятки хороших способів виявлення виявлення меж у відповідності з вашими потребами, але давайте продовжимо це просто зараз, якщо ви зацікавлені, я можу запропонувати вам більше варіантів!

Тож ідея була б подібною до наведеної вище, з тією різницею, що ви можете подивитися на ширше околиці та використовувати набір ваг для сортування зразків, якщо хочете. Як правило, ви проводите згортку свого зображення з ядром, що дає в результаті хорошу інформацію про градієнт.
Дуже поширеним вибором є ядро ​​Sobel

                                   введіть тут опис зображення

Які відповідно дають вам градієнти у напрямку x та y:

                                  Зі старого pdf я писав давно.

GradientMagnitude=(Gradientx)2+(Gradienty)2

Тоді ви можете порогувати так само, як я згадав вище.

Як бачите, це ядро ​​надає більшої ваги центральному пікселю, тому ефективно обчислює градієнт + трохи згладжування, що традиційно допомагає (часто зображення гаусовим розмитим, щоб усунути невеликі краї).

Вищезазначене працює досить добре, але якщо ви не любите згладжування, ви можете використовувати ядра Prewitt:

                                                   введіть тут опис зображення

(Зауважте, що я поспішаю, незабаром напишу належний відформатований текст замість зображень!)

Дійсно, є набагато більше ядер і методів пошуку виявлення країв у процесі зображення, а не в графіці в реальному часі, тому я виключив більш складні (каламбур не призначені) методи, напевно, вам би було добре з функціями dFdx / y .


Дуже приємне пояснення cifz, але що робити, якщо в певній ситуації градієнт не видно? Наприклад, у задній частині куба немає джерела світла, тому градієнт не видно. Тоді цей процес виявлення краю, який ви описуєте, не працює, я прав?
enne87

Якщо ви використовуєте відкладений візуалізатор, ви можете зробити те ж саме, але у звичайному буфері або знову ж таки, якщо у вас є попередній заряд, ви можете застосувати алгоритм до глибини. І все-таки ви маєте рацію, підхід до екранного простору може бути не ідеальним у всіх випадках :) Яке рішення є життєздатним, багато в чому залежить від вашого бюджету на цей ефект, наскільки складна ваша сцена.
cifz

Потенційно, якщо це дійсно важливо для вашої гри, дуже легким, але потенційно оподатковуючим, буде обчислення градієнта на сусідніх нормалах для кожної вершини (офлайн у час завантаження) та передавання цього фактору як додатковий атрибут вершини.
cifz

Thangs знову cifz для вашої допомоги. Ну, що я хочу досягти - це розробити CAD / CAM рішення, яке буде схоже на це: youtube.com/watch?v=-qTJZtYUDB4 І мені дуже хотілося б знати, як їм вдалося видати всі чорні краї, зморшки і хребти. cifz, як ти вважаєш, як спеціаліст із графічного програмування, що вони досягли цього вигляду, використовуючи один із підходів до екрану? А може, обчисливши градієнт на сусідніх нормалах? Я дуже хочу знати, як це можна зробити. Знову дякую!
enne87

1
Не потрібно нікому платити, просто починайте читати кілька навчальних посібників в Інтернеті, купуйте книжки та навчайтесь важко :) Це буде дуже корисно в кінці!
cifz

3

На всякий випадок, коли комусь також потрібно виявити краї: Ось приємна стаття про те, як відобразити каркас, і ця стаття пояснює, як показувати лише краї.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.