Уроки по OpenGL с сайта OGLDev


Урок 34 - GLFX - An OpenGL Effect Library

Этот урок слегка отличается от предыдущих. Вместо изучения возможностей технологий OpenGL мы собираемся рассмотреть GLFX, библиотеку эффектов OpenGL. Эффект - это текстовый файл, который, возможно, содержит несколько шейдеров и упрощает комбинирование их в программе. Это позволяет обойти ограничение функции glShaderSource(), которая требует указать текст только одного этапа шейдеров. Она насильно заставляет использовать различные текстовые файлы для каждого шейдера (или различные буферы, как мы делали в прошлых уроках). Помещение всех шейдеров в один файл упрощает обмен определением структур между ними. Кроме того, GLFX предоставляет простой API для перевода эффектов в программу GLSL, что частично скрывает сложность функций OpenGL.

Идея файлов эффектов не нова. На самом деле, Microsoft уже годами раннее реализовало это в мире DirectX. Я уверен, что игровые студии имеют их собственный инструментарий, но к стыду говорят, в OpenGL нет для этого стандарта. Библиотека эффектов, которую мы будем использовать, - свободный проект Max Aizenshtein. Домашняя страница библиотеки тута.

Существует 2 способа установки GLFX. Если вы используете Ubuntu, то вы можете просто установить deb пакет из моего ppa на launchpad.net, или вы можете скачать исходный код и собрать самостоятельно.

Способ 1 - установка пакета GLFX для Ubuntu

  • Для начала, вы должны добавить мой ppa к списку источников apt. Это можно сделать 2 способами:
    • Запустить в терминале 'add-apt-repository ppa:etay-meiri/ppa'.
    • Или вы можете вручную добавить следующий репозиторий /etc/apt/sources.list:
      • deb http://ppa.launchpad.net/etay-meiri/ppa/ubuntu oneiric main
      • deb-src http://ppa.launchpad.net/etay-meiri/ppa/ubuntu oneiric main
  • Запустить 'apt-get update'
  • А затем 'apt-get install libglfx'

Способ 2 - установка из исходников

Получаем исходники и собираем их с помощью следующих команд:

  • $ svn checkout http://glfx.googlecode.com/svn/trunk/ libglfx
  • $ cd libglfx
  • $ ./configure –prefix=/usr
  • $ make
  • # make install

Внимание: GLFX зависит от GLEW. В этом нет проблемы, если вы используете эти уроки как фреймворк или ранее использовали GLEW в своем приложении. Если нет, то вернитесь во 2 урок для информации об инициализации GLEW.

Прямиком к коду!

Внедрении GLFX в проект

Добавьте следующее для получения доступа к api GLFX:

#include <glfx.h>

Создание указателя на эффект:

int effect = glfxGenEffect();

Проход по файлу эффекта (мы получим его содержание мгновенно):

if (!glfxParseEffectFromFile(effect, "effect.glsl")) {
#ifdef __cplusplus	// C++ error handling
    std::string log = glfxGetEffectLog(effect);
    std::cout << "Error parsing effect: " << log << std::endl;
#else // C error handling
    char log[10000];
    glfxGetEffectLog(effect, log, sizeof(log));
    printf("Error parsing effect: %s:\n", log);
#endif
    return;
}

Компилирование программы (комбинация из VS, FS и прочих) определяется в файле эффекта следующим образом:

int shaderProg = glfxCompileProgram(effect, "ProgramName");

if (shaderProg < 0) {
    // таже ошибка с указателем, что и ранее
}

Теперь программа может быть использована в OpenGL как обычно:

glUseProgram(shaderProg);

Так как эффект больше не требуется, то удаляем его через

glfxDeleteEffect(effect);

Использование GLFX

Теперь у нас есть базовая инфраструктура, поэтому давайте погрузимся в файлы эффекта. Прелесть GLFX в том, что вы можете продолжить писать шейдеры GLSL практически в том же стиле, что и ранее. Есть несколько отличий, на которых мы фокусируемся.

Добавился раздел 'program' для комбинации этапов шейдеров в полной программе GLSL.

program Lighting
{
    vs(410)=VSmain();
    fs(410)=FSmain();
};

В примере выше файл эффекта где-то содержит определение функций VSmain() и FSmain(). Раздел 'program' определяет программу OpenGL с названием 'Lighting'. Вызов glfxCompileProgram(effect, "Lighting") приведет к компиляции и линковки VSmain() и FSmain() в единую программу. Оба шейдера будут компилироваться в GLSL версии 4.10 (аналогично объявлению '#version 410' в обычном GLSL).

Использование 'shader' вместо 'void' для объявления главной функции шейдера.

Главная точка входа в шейдер должна быть объявлена как 'shader' вместо 'void'. Вот пример: void calculate_something() { … }

shader VSmain()
{
    calculate_something();
}

Включение нескольких шейдеров и программ в единый файл эффекта.

Вы можете разместить несколько разделов 'program' в единственный файл эффекта. Просто вызовете glfxCompileProgram() для каждой программы, которую хотите использовать.

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

Вместо определения in/out переменных в глобальной секции шейдера мы можем использовать структуру GLSL и обмениваться ей между несколькими этапами шейдеров. Вот пример:

struct VSInput
{
    vec3 Position;
    vec2 TexCoord;
    vec3 Normal;
};

struct VSoutput
{
    vec2 TexCoord;
    vec3 Normal;
};

shader VSmain(in VSInput VSin, out VSOutput VSout)
{
    // преобразуем 'VSin' и обновляем 'VSout'
}

shader FSmain(in VSOutput FSin, out vec4 FragColor)
{
    // 'FSin' соответствует 'VSout' из VS. используем ее
    // для вычисления света и записываем результат в 'FragColor'
}

Использование включений для обмена функционалом между файлами эффектов.

Ключевое слово 'include' может быть использовано для включения одного файла эффекта в другой:

#include "another_effect.glsl"

Предостережение с включением файлов в том, что они не пробегаются GLFX. Они просто добавляются как есть в место, указанное словом 'include'. Это значит, что вы можете поместить только чисто GLSL код в них, без GLFX. Совет: поскольку часть синтаксиса GLSL аналогична C/C++ (#define), вы можете даже обмениваться определениями между файлом эффекта и вашем приложением.

Использование суффикса структур для определения позиции атрибута

В прошлых уроках мы использовали ключевое слова 'layout(location = …)' для определения позиции входящего атрибута в VS. Поместив двоеточие перед числом после входящего параметра VS мы можем достичь того же эффекта. Вот пример:

struct VSInput1
{
    vec3 Position;
    vec2 TexCoord;
};

struct VSInput2
{
    vec3 Normal;
    vec3 Tangent;
};

shader VSmain(in VSInput1 VSin : 5, in float colorScale : 10, in VSInput2 : 12)

VS выше получает позицию в атрибуте 5, координаты текстуры в 6, цвет в 10, нормаль в 12 и тангент в 13. Идея крайне проста - число после двоеточия определяет его позицию. В случае структур вы определяете позицию только первого атрибута. Остальные будут получать следующие значения согласно их типу (т.е. вектор возьмет 1 атрибут, а матрица 4x4 - 4 атрибута). Если суффикс отсутствует, то отсчет начнется с 0.

Использование 'interface' вместо 'struct' для размещения квалификаторов

GLSL предоставляет несколько квалификаторов, такие как 'flat' и 'noperspective', которые могут быть размещены перед атрибутами, которые посылаются из VS в FS. Эти квалификаторы не могут быть использованы для членов структур. Решение, которое предоставляет GLFX - новое ключевое слово 'interface', которое позволяет то, что 'struct' не может. 'interface' может быть только передан между этапами шейдеров. Если вам требуется передать его целиком в другую функцию, то вы должны копировать его содержимое в структуру. Пример:

interface foo
{
    flat int a;
    noperspective float b;
};

struct bar
{
    int a;
    float b;
}

shader VSmain(out foo f)
{
    // ...
}

void Calc(bar c)
{
    // ...
}

shader FSmain(in foo f)
{
    struct bar c;
    c.a = f.a;
    c.b = f.b;

    Calc(c);
}

Внимание: 'interface' - это ключевое слово, зарезервированное на будущее (согласно OpenGL 4.2). Его использование в GLFX будет зависеть от изменений в спецификации OpenGL.

Совет: используйте 'glfxc' для проверки файлов эффектов

'glfxc' - это приложение, часть GLFX. Он проходит по файлу эффекта, компилирует его и сообщит об ошибках. Запускается от так:

glfxc <effect file name> <program name>

Демо

Код этого урока был изменен для работы с GLFX. Поскольку изменения незначительны, я не буду показывать их. Лучше посмотрите на исходники классов Technique и LightingTechnique. Кроме того, шейдеры, который используются в 'lighting_technique.cpp', были перемещены в файл эффекта, названный 'lighting.glsl' в папке 'shaders'. Этот файл содержат те же шейдеры; вы уже знакомы с ними. Они были слегка изменены согласно правилам выше.

powered byDisqus