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");
miviclin
источник

Ответы:

16

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

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

Где бы ни были определены шейдеры, вы можете обращаться к именам так же, как в своем примере. Использование строкового литерала приемлемо для шейдеров, так как эти значения вряд ли изменятся после их реализации.

Однако, в конце концов, решать вам. То, как вы сейчас это делаете, прекрасно работает, если это не доставляет вам хлопот.

MichaelHouse
источник
2
Наличие ваших шейдеров в отдельных файлах также означает, что вы можете использовать свои удобные редакторы шейдеров и иметь полную подсветку синтаксиса и даже просматривать их перед тестированием в своей программе, если ваша поддержка это поддерживает.
Raceimaztion
6
Единственная реальная причина наличия шейдеров в строке - быстрые тесты и учебники ... где обработка файлов добавляет большую часть «ненужного кода».
Яри ​​Комппа
2
Вы также можете реализовать горячую перезагрузку для файлов шейдеров, что позволяет отлаживать изменения без перезапуска игры. Производительность ++
Лиосан
Мне нравится идея читать их из файла и иметь отдельный класс Shader. Видя их всегда в одной строке, сбивало меня с толку, потому что я не знал, так ли это обычно, как они определены, или просто для учебных целей. Благодарность!
Мивиклин
8

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

  • Небольшие примеры, где есть только пара шейдеров, имеют тенденцию жестко кодировать их как строки, чтобы избежать обработки файлов, как прокомментировал Яри Комппа
  • Лучше использовать отдельные файлы, где вы можете иметь подсветку синтаксиса и правильное форматирование. Вы также можете кодировать простую систему отладки, которая отслеживает изменения в этих файлах и применяет измененный шейдер на лету во время игры.
  • Когда количество материалов увеличивается, шейдерный генератор становится почти необходимостью. По сути, вы определяете общие фрагменты, такие как «фрагмент фрагмента нормального отображения шейдера», и составляете свои полные шейдеры, включая нужные компоненты.
    • Вы можете использовать жестко запрограммированные фрагменты строк, но это очень быстро запутывает, так что, опять же, файлы - хорошая идея.
    • Вы можете иметь биты кода в отдельных файлах (или в одном и том же) или альтернативно использовать ubershader / supershader, где вы используете препроцессор (или унифицированные флаги) для включения / выключения вещи.

Что касается атрибутов и унифицированных имен и тому подобного, вы просто используете согласованные имена для всех шейдеров.

Тапио
источник
Я обязательно перенесу свои шейдеры в отдельный файл. Благодарность!
Мивиклин