Как создать систему эффектов, подобную CgFx? - PullRequest
1 голос
/ 18 октября 2011

Графический движок Seriouse, такой как CryEngine3, Unreal Engine 3, имеет настроенный язык шейдеров и систему эффектов. Пытаясь найти какую-то систему эффектов для моей небольшой графической платформы, похоже, что nvidia CgFx - единственный выбор (кажется, у Khronos был проект под названием glFx, но страница проекта теперь 404).

У меня есть несколько причин сделать собственную систему эффектов:

  1. Мне нужно больше контроля над тем, как и когда передавать параметры шейдера.
  2. Чтобы повторно использовать фрагменты шейдера, я хочу создать механизм, подобный макросу на c ++. Также полезно использовать макрос для условной компиляции, а также способ, которым CryEngine использовал для создания различных эффектов.
  3. Похоже, у GLSL нет такой системы эффектов

так мне интересно, как создать систему эффектов? Нужно ли писать грамматический парсер с нуля или уже есть код / ​​инструменты, способные сделать это?

PS: я использую OpenGL с GLSL и CG.

Ответы [ 2 ]

4 голосов
/ 18 октября 2011

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

Это ничто по сравнению с тем, что можно найти в UDK, но довольно удобно, и я думаю, вы пытаетесь реализовать что-то подобное?

Если это так, то вот несколько вещей, которые нужно сделать.Во-первых, вам нужно создать класс для абстрактной обработки параметров шейдера (привязка, настройка и т. Д.). Что-то вроде этого:

class IShaderParameter
{
protected:
    IShaderParameter(const std::string & name)
        : m_Uniform(-1)
        , m_Name(name)
    {}
    GLuint m_Uniform;
    std::string m_Name;
public:
    virtual void Set(GLuint program) = 0;
};

Затем для статических параметров вы можете просто создать перегрузку следующим образом:

template < typename Type >
class StaticParameter
    : public IShaderParameter
{
public:
    StaticParameter(const std::string & name, const Type & value)
        : IShaderParameter(name)
        , m_Value(value)
    {}
    virtual void Set(GLuint program)
    {
        if (m_Uniform == -1)
            m_Uniform = glGetUniformLocation(program, m_Name.c_str());
        this->SetUniform(m_Value);
    }
protected:
    Type m_Value;
    void SetUniform(float value) { glUniform1f(m_Uniform, value); }
    // write all SetUniform specializations that you need here
    // ...
};

И, следуя той же идее, вы можете создать тип «параметра динамического шейдера».Например, если вы хотите иметь возможность привязать параметр источника света к своему шейдеру, создайте тип специализированного параметра.В его конструкторе передайте id источника света, чтобы он знал, как получить источник света в методе Set.Немного поработав, вы можете получить целый набор параметров, которые затем сможете автоматически привязать к сущности вашего двигателя (параметры материала, параметры освещения и т. Д.)

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

<shader>
    <param type="vec3" name="lightPos">light_0_position</param>
    <param type="vec4" name="diffuse">material_10_diffuse</param>
    <vertexShader>
      ... a CDATA containing your shader code
    </vertexShader>
</shader>

В моем движке «light_0_position» означало бы параметр света, 0 - это ID источника света, а position - параметр, который нужно получить.Связывание между параметром и фактическим значением было выполнено во время загрузки, поэтому не было больших накладных расходов.

В любом случае, я не буду отвечать, если это ответит на ваш вопрос, и не воспринимаю эти примеры кода слишком серьезно (HLSLШейдеры OpenGL работают совершенно по-другому, и я не эксперт по OpenGL ^^) но, надеюсь, это даст вам несколько подсказок:)

0 голосов
/ 19 октября 2011
  1. Не могли бы вы уточнить это? Работая напрямую с OpenGL, вы получаете полный контроль над параметрами, передаваемыми в графический процессор. Что именно вам не хватает?

  2. (и 3.) GLSL поддерживает повторное использование кода. Вы можете иметь библиотеку шейдеров, предоставляющих различные функции. Чтобы использовать любую функцию, вам просто нужно предварительно объявить ее в клиентском шейдере (vec4 get_diffuse();) и присоединить объект шейдера, реализующий функцию, к программе шейдера перед установкой связи.

...