Unity - керівництво поверхневі шейдери з використанням тесселяції dx11

У поверхневих шейдерах є деяка підтримка GPU тесселяции DirectX 11. Ідея така:

  • Тесселяція визначається модифікатором tessellate: FunctionName. Ця функція розраховує фактори тесселяции на кордоні і всередині трикутника.
  • При використанні тесселяции, після неї викликається "вершинний модифікатор" (vertex: FunctionName) для з кожної згенерованої вершини в доменному шейдера. Тут ви зазвичай зробили б накладення карт зсуву.
  • Опціонально поверхневі шейдери можуть виробляти розрахунок phong тесселяции для згладжування поверхні моделі, навіть без накладення карт зсуву.

Поточні обмеження підтримки тесселяції:

  • Тільки трикутний домен - немає квадов, немає isoline тесселяции.
  • Коли використовується тесселяция, шейдер автоматично компілюється з використанням Shader Model 5.0, тому він буде працювати тільки під DX11.

Ні GPU тесселяции, зміщення в модификаторе вершин

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

Шейдер, наведений вище, вельми стандартний, цікаві місця:

  • Верховий модифікатор disp здійснює вибірку з карти зсувів і зрушує вершини уздовж їх нормалей.
  • Використовується для користувача структура "введення вершинних даних" (appdata) замість структури за замовчуванням appdata_full. Поки вона не потрібна, але для тесселяції ефективніше використовувати якомога меншу структуру.
  • Так як наші вершинні координати не мають 2й UV координати, ми додаємо директиву nolightmap для виключення карт освітлення.

Ось як деякі прості об'єкти будуть виглядати при використанні цього шейдера:

Unity - керівництво поверхневі шейдери з використанням тесселяції dx11

Фіксована кількість тесселяции

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

Функція тесселяции tessFixed в нашому шейдера повертає чотири чинника тесселяции у вигляді одного значення float4: три фактори для кожної сторони трикутника і один фактор для внутрішньо області трикутника. Тут ми просто повертаємо постійне значення, яке зазначено у властивостях матеріалу.

Unity - керівництво поверхневі шейдери з використанням тесселяції dx11

Тесселяція на основі відстані

Ми також можемо змінювати рівень тесселяції в залежності від відстані до камери. Наприклад, ми могли б оголосити два значення відстані; відстань, на якому тесселяция максимальна (скажімо, 10 метрів), і відстань, у міру наближення до якого рівень тесселяції плавно падає (скажімо, 20 метрів).

Тут функція тесселяции отримує три параметри; дані вершин трьох кутів трикутника до тесселяции. Це необхідно для розрахунку рівнів тесселяції, які залежать від поточного положення вершин. Ми включаємо вбудований допоміжний файл Tessellation.cginc і викликаємо з нього функцію UnityDistanceBasedTess для здійснення всієї роботи. Ця функція розраховує відстань до камери кожної вершини і витягує кінцеві фактори тесселяции.

Unity - керівництво поверхневі шейдери з використанням тесселяції dx11

Тесселяція на основі довжини сторони

Тесселяція, заснована тільки на відстані хороша тільки коли розміри трикутників досить схожі. На зображенні, представленому вище, ви можете помітити, що у об'єктів з маленькими трикутниками тесселяция занадто сильна, в той час як об'єкти з великими трикутниками недостатньо тесселіровани.

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

Тут знову, ми просто викликаємо функцію UnityEdgeLengthBasedTess з Tessellation.cginc для здійснення всієї роботи.

Unity - керівництво поверхневі шейдери з використанням тесселяції dx11

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

Phong тесселяция

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

Поверхневі шейдери Unity можуть автоматично розраховувати phong тесселяцию за допомогою директиви компіляції tessphong: VariableName. Ось приклад шейдера:

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

Unity - керівництво поверхневі шейдери з використанням тесселяції dx11

Приклади освітлення в поверхневих шейдерах

Програмування вершинних і фрагментних (піксельних) шейдеров