OpenGL: Де потрібно розмістити шейдери?


17

Я намагаюся навчитися OpenGL ES 2.0 і мені цікаво, що є найпоширенішою практикою «керування» шейдерами.
Я задаю це запитання, тому що в знайдених нами прикладах (як, наприклад, в демонстраційному інтерфейсі API, який надається з Android sdk), я зазвичай бачу все всередині класу GLRenderer, і я вважаю за краще окремі речі, щоб мати можливість, наприклад, об'єкт GLImage, який я можу використовувати повторно, коли хочу малювати текстурований квадратик (я зосереджуюсь на 2D лише в даний момент), як і в коді OpenGL ES 1.0. Майже в кожному знайденому нами прикладі шейдери просто визначаються як атрибути класу. Наприклад:

public class Square {

public final String vertexShader =
        "uniform mat4 uMVPMatrix;\n" +
        "attribute vec4 aPosition;\n" +
        "attribute vec4 aColor;\n" +
        "varying vec4 vColor;\n" +
        "void main() {\n" +
        "  gl_Position = uMVPMatrix * aPosition;\n" +
        "  vColor = aColor;\n" +
        "}\n";

public final String fragmentShader =
        "precision mediump float;\n" +
        "varying vec4 vColor;\n" +
        "void main() {\n" +
        "  gl_FragColor = vColor;\n" +
        "}\n";
// ...
}

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

1) Чи є наведений вище код загальним способом визначення шейдерів (загальнодоступних властивостей останнього класу)?
2) Чи повинен я мати окремий клас Шейдер?
3) Якщо шейдери визначені поза класом, який їх використовує, то як я можу знати назви їх атрибутів (наприклад, "aColor" у наступному фрагменті коду), щоб я міг їх зв'язати?

colorHandle = GLES20.glGetAttribLocation(program, "aColor");

Відповіді:


16

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

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

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

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


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

6
Єдина реальна причина наявності шейдерів у рядку - це швидкі тести та навчальні посібники.
Jari Komppa

2
Ви також можете реалізовувати гаряче перезавантаження у файлах шейдерів - дозволяючи налагоджувати зміни без повторного запуску гри. Продуктивність ++
Liosan

Мені подобається, що я читаю, як вони утворюють файл та мають окремий клас Shader. Бачити їх завжди у струні мене бентежило, бо я не знав, чи це саме те, як їх зазвичай визначають, або просто для навчальних цілей. Спасибі!
miviclin

8

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

  • Невеликі приклади, коли є лише кілька шейдерів, як правило, жорстко кодують їх як рядки, щоб уникнути обробки файлів, як коментує Jari Komppa
  • Краще використовувати окремі файли, де можна виділити синтаксис та належне форматування. Ви також можете кодувати просту систему налагодження, яка спостерігає за змінами в цих файлах і застосовує модифікований шейдер під час руху під час гри.
  • Коли кількість матеріалів збільшується, генератор шейдерів стає майже необхідністю. В основному ви визначаєте загальні фрагменти, такі як "фрагмент шейдера, звичайний фрагмент відображення", і складаєте ваші повні шейдери, включаючи потрібні компоненти.
    • Ви можете використовувати жорстко зашифровані фрагменти рядків, але це швидко стає безладним, тому файли ще раз є хорошою ідеєю.
    • Ви можете або мати біти коду в окремих файлах (або однакових), або альтернативно використовувати ubershader / supershader, де ви використовуєте препроцесор (або рівномірні прапори), щоб увімкнути / вимкнути речі.

Що стосується атрибутів та єдиних імен та таких, ви просто використовуєте послідовну назву для всіх шейдерів.


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