Як у матеріальній системі на основі графіків я можу підтримувати різні типи введення та виведення?


11

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

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


Фон:

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

Щоб зробити цю систему трохи гнучкішою, я зазвичай пишу її таким чином, що дозволяє мені намагатися передати уніформу будь-якого імені / типу [тобто: SetUniform_Vec4 ("AmbientColor", colorVec4); який би встановити AmbientColor форму для конкретного 4d вектора під назвою «colorVec4» , якщо що рівномірна існує в матеріалі.] .

class Material
{
    private:
       int shaderID;
       string vertShaderPath;
       string fragSahderPath;

       void loadShaderFiles(); //load shaders from files at internal paths.
       void buildMaterial(); //link, compile, buffer with OpenGL, etc.      

    public:
        void SetGenericUniform( string uniformName, int param );
        void SetGenericUniform( string uniformName, float param );
        void SetGenericUniform( string uniformName, vec4 param );
        //overrides for various types, etc...

        int GetUniform( string uniformName );
        float GetUniform( string uniformName );
        vec4 GetUniform( string uniformName );
        //etc...

        //ctor, dtor, etc., omitted for clarity..
}

Це працює, але це здається поганою системою через те, що клієнт класу Material має доступ до уніформи тільки на віру - користувач повинен бути дещо обізнаний з уніформами, які є у кожного матеріального об'єкта, тому що вони змушені передайте їх за своїм ім'ям GLSL. Це не велика справа, коли всього 1-2 люди працюють із системою, але я не можу уявити, що ця система взагалі дуже добре масштабується, і перш ніж зробити наступну спробу програмування системи візуалізації OpenGL, я хочу рівнятись трохи вгору.


Питання:

Ось де я зараз перебуваю, тому я намагався вивчити, як інші двигуни рендерингу обробляють свої матеріальні системи.

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

Як я можу сказати, реалізація такої системи була б таким же простим класом MaterialNode з різноманітними підкласами (TextureNode, FloatNode, LerpNode тощо). Де кожен підклас MaterialNode мав би MaterialConnections.

class MaterialConnection
{
    MatNode_Out * fromNode;
    MatNode_In * toNode;
}

class LerpNode : MaterialNode
{
    MatNode_In x;
    MatNode_In y;
    MatNode_In alpha;

    MatNode_Out result;
}

Це сама основна ідея, але я трохи не впевнений у тому, як би працювали кілька аспектів цієї системи:

1.) Якщо ви подивитесь на різні «Матеріальні вирази» (вузли), якими користується Unreal Engine 4 , ви побачите, що в кожному з них є вхідні та вихідні з'єднання різних типів. Деякі вузли виводять плаває, деякі вихідний вектор2, деякі вихідний вектор4 і т. Д. Як я можу вдосконалити вузли та з'єднання вище, щоб вони могли підтримувати різні типи введення та виведення? Чи буде підкласифікація MatNode_Out за допомогою MatNode_Out_Float та MatNode_Out_Vec4 (і так далі) бути мудрим вибором?

2.) Нарешті, як ця система стосується шейдерів GLSL? Подивившись знову на UE4 (як і на інші системи, пов'язані вище), користувачеві необхідно врешті-решт підключити якийсь вузол матеріалу у великий вузол з різними параметрами, що представляють параметри шейдера (базовий колір, металічність, блиск, емісію та ін.) . Моє первісне припущення було те, що UE4 мав якийсь жорсткий кодований "головний шейдер" з різноманітною формою, і все, що користувач робить у своєму "матеріалі", просто передається "головному шейдеру", коли вони підключають свої вузли до " головний вузол '.

Однак у документації UE4 зазначено:

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

Якщо це правда, чи генерує ця система справжній сценарій шейдера? Як саме це працює?


1
Пов’язане з вашим запитанням: gameangst.com/?p=441
glampert

Відповіді:


10

Я спробую відповісти, наскільки мені відомо, мало знаючи про конкретний випадок UE4, а про загальну техніку.

Матеріали на основі графіків - це стільки ж програмування, скільки і написання коду самостійно. Це просто не так, як людям, що не мають коду, що полегшує процес. Отже, коли дизайнер пов'язує вузол "Додати", він в основному пише add (value1, value2) і пов'язує вихід з чимось іншим. Це те, що вони означають, що кожен вузол генерує код HLSL, або його виклик функції, або просто прямі вказівки.

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

У випадку UE4, якщо вони заявляють, що він перетворений на HLSL, я припускаю, що вони використовують інструмент перетворювача, який здатний перетворити байт-код HLSL в байт-код GLSL, тому його можна використовувати на платформах GL. Але в інших бібліотеках просто є кілька компіляторів шейдерів, які будуть читати графік і безпосередньо генерувати потрібні джерела мови затінення.

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

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

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

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

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

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

Щоб завершити його, я пропоную файл .material просто обробити кожен графік. Під час розробки він міг би містити текстовий формат для налагодження, а потім упакований або компільований у двійковий для випуску. Кожен .матеріал складатиметься з N вузлів та N з'єднань, подібних до бази даних SQL. Кожен вузол мав би N полів із назвою та деякими прапорами для типів, що приймаються, якщо його вхід чи вихід, якщо типи зроблені та ін. Структура даних для виконання завантаженого матеріалу буде такою ж плоскою та простою, тому редактор може легко адаптувати його і зберігати назад у файл.

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

Повідомте мене, якщо вам потрібні додаткові деталі чи якісь виправлення у моїй відповіді, я втратив огляд усього тексту.


Я не можу подякувати вам за написання такої складної та чудової відповіді. Я відчуваю, що у мене прекрасна ідея, куди мені піти звідси! Дякую!
MrKatSwordfish

1
Немає проблемних товаришів, сміливо повідомте мене, якщо вам потрібна додаткова допомога. Я фактично працюю над чимось рівноцінним для власних інструментів, тому, якщо ви хочете торгувати думками, будьте моїм гостем! Приємного дня: D
Грімшо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.