Шейдеры GLSL [ч.2 - Добавление в игру] [upd: ч.2.5 - логирование ошибок]

Шейдеры GLSL [ч.2 - Добавление в игру] [upd: ч.2.5 - логирование ошибок]

Версия(и) Minecraft
любая
Доброго времени суток! о/

В этой части я расскажу, как добавить в игру созданный в предыдущей части вершинный шейдер. Если вы не читали её и вообще понятия не имеете, что такое шейдер, вам сюда: Шейдеры GLSL [ч.1 - Fragment Shaders]

Итак, без лишних слов, начинаем!
Сразу скажу: все программы, директивы и прочее для OpenGL хранится в виде числовых идентификаторов. И всё, что нам нужно - получить этот идентификатор. Да, вот настолько просто создать и добавить собственный шейдер. Но обо всём по порядку.

Для начала нам нужно загрузить в наш мод код шейдера. Это не более чем строка, так что да, шейдеры можно писать прямо внутри программы в переменной типа String, однако по мне это дурной тон.
Как вы это будете делать значения абсолютно не имеет, а чтение из файла базовый навык, и расписывать то, что все и так знают не вижу смысла.
В таком случае совет:
Как по мне, лучше всего использовать java.io.BufferedReader#readLine для чтения и java.lang.StringBuilder#append для объединения строчек файла.

В результате получим код шейдера в строке String shaderCode
Теперь самое время загрузить его!
Создадим переменную-идентификатор нашего будущего шейдера и попросим OpenGL присвоить ей новое значение. Поскольку это фрагментный шейдер, в параметрах функции мы так и напишем:
int shaderID = ARBShaderObjects.glCreateShaderObjectARB(ARBFragmentShader.GL_FRAGMENT_SHADER_ARB);
Закрепим за нашим ID исходный код шейдера (String shaderCode, описанный выше)
ARBShaderObjects.glShaderSourceARB(shaderID, shaderCode);
И скомпилируем его!
ARBShaderObjects.glCompileShaderARB(shaderID);
Готово! ID можно смело использовать для получения нашего шейдера.
Теперь создадим саму программу (ведь Шейдер - это программа, которая выполняется в цикле рендеринга графики... Ну вы помните):
int programID = ARBShaderObjects.glCreateProgramObjectARB();
Прицепим к ней наш фрагментный шейдер..:
ARBShaderObjects.glAttachObjectARB(programID, shaderID);
И слинкуем (объединим программу и шейдер)!
ARBShaderObjects.glLinkProgramARB(programID);
Всё, теперь ваш programID и будет тем самым числовым идентификатором, который будет впоследствии вызываться вашим рендером.

Ну что, проверим как это всё выглядит в игре?
Опять же, не стану объяснять, как рендерить блок/предмет/моба/ещё что, ибо раз вы взялись за написание шейдеров, предполагается, что простейший рендер вам уже подвластен.
Как же вызвать наш шейдер в рендере? Всего-то одна строка:
ARBShaderObjects.glUseProgramObjectARB(programID);
Важно: вызывать эту строку нужно два раза:
Перед
отрисовкой объекта (например, model.renderAll())
После отрисовки, но вместо programID поставить 0.
Всё. Теперь ваш шейдер работает и накладывается на каждый полигон вашей модельки!
И да, запомните:
Включать-выключать один и тот же шейдер для каждого объекта - очень плохо.

Примечание: если вы хотите передать в шейдер какой-нибудь uniform, делайте так:
Java:
// Получите ID необходимой переменной с модификатором uniform по её имени в программе:
int uniformID = ARBShaderObjects.glGetUniformLocationARB(proramID, "uniformName");
// И присвойте необходимое значение ПО ТИПУ
ARBShaderObjects.glUniform%%ARB(uniformID, VALUE);
// Вместо %% - необходимый вам тип; все типы смотрите по crtl+пробелу

Например, время:
Java:
// В шейдере:
uniform float time;

// В рендере:
int timeID = ARBShaderObjects.glGetUniformLocationARB(proramID, "time");
ARBShaderObjects.glUniform1fARB(timeID, Minecraft.getMinecraft().theWorld.getTotalWorldTime() / 20.0F);

4y_ll4BwOyA.jpg

Браво! Теперь вы тоже можете в шейдеры! :D даже раньше, чем Польша в космос :D

Ошибки:
Иногда у вас могут возникнуть проблемы при создании, сборке или линковке шейдера, поэтому эти случаи нужно уметь обрабатывать.
1. Первое, что может произойти - .glCreateShaderObjectARB() и/или .glCreateProgramObjectARB() вернёт ноль. Тогда дальнейшая линковка и прочее не будут иметь смысла, так что проверяйте if (shaderID != 0)

2. Ошибка компиляции .glCompileShaderARB(). Обрабатывается примерно так:
Java:
if (ARBShaderObjects.glGetObjectParameteriARB(shaderID,
      ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB) == GL11.GL_FALSE)
   throw new RuntimeException("Shader compilation error!\n" +
      ARBShaderObjects.glGetInfoLogARB(shaderID, ARBShaderObjects.
      glGetObjectParameteriARB(shaderID, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB)));
Не забудьте удалить неверно скомпилированный объект: ARBShaderObjects.glDeleteObjectARB(shaderID);

3. Ошибка линковки .glLinkProgramARB()
Java:
if(ARBShaderObjects.glGetObjectParameteriARB(programID,
    ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB) == GL11.GL_FALSE) // exception
    // Информация через .glGetInfoLogARB

4. Валидация программы и обработка ошибки:
Java:
// Проверяем полученную программу
ARBShaderObjects.glValidateProgramARB(programID);
// Если в ней ошибка - выбрасываем исключение
if (ARBShaderObjects.glGetObjectParameteriARB(programID,
    ARBShaderObjects.GL_OBJECT_VALIDATE_STATUS_ARB) == GL11.GL_FALSE) // exception

Информация: GitHub.

Всего хорошего!
Автор
AlexSoсol
Просмотры
3,935
Первый выпуск
Обновление
Оценка
4.00 звёзд 1 оценок

Другие ресурсы пользователя AlexSoсol

Последние обновления

  1. Шейдеры GLSL [ч.2.5 - Логирование ошибок]

    Добавлена часть про обработку и логирование ошибок.

Последние рецензии

Отлично, однако нет примеров.
Сверху