#include с пользовательским вводом-выводом для GLSL/C?

У меня два вопроса, два очень важных:

  1. Существует ли препроцессор C, который сможет использовать любую пользовательскую функцию для поиска файла, вызываемого #include? Потому что, скажем, мои коды хранятся в ZIP-файле или где-то еще, и я полагаюсь на PhysFS, чтобы получить к ним доступ, а не разархивировать их. Существует ли препроцессор C с открытым исходным кодом, который может работать с этим, вместо того, чтобы ограничиваться обычным fopen?
  2. Можно ли использовать собственный или стандартный препроцессор C в коде GLSL? Я знаю, что у GLSL уже есть препроцессор, но ему не хватает #include особенность, и я хочу исправить это.
  3. Можно ли объединить два вышеперечисленных, чтобы иметь программу или видеоигру, где исходные коды GLSL хранятся в файле ZIP или PK3 (следовательно, доступ к нему осуществляется с помощью PhysFS или любой другой вещи ввода-вывода), а пользовательский / модифицированный препроцессор C - это используется для обработки #include и получения включенных источников?

Я спрашиваю об этом, потому что у меня нет желания писать свой собственный препроцессор C для GLSL, если это не является абсолютно необходимым, и предпочел бы использовать существующий для реализации #include с пользовательским вводом-выводом.

Практически единственная причина, по которой мне нужен препроцессор C, это то, что я хочу #includeи я хочу это с моей собственной вещью ввода-вывода.

Примеры функций препроцессора, которые я хотел бы реализовать:

  1. Предварительно весь уже обработанный исходный код #version 450, или же #version 310 es, так же как #extension GL_ARB_separate_shader_objects : enable
    1. Включая константы времени выполнения. Некоторые говорят, что униформа может быть лучше для этой цели, но заранее определенные неоднозначные константы, вероятно, тоже подойдут.
    2. Повторное использование функций.

Один пример предполагаемого использования:

ColourGradient.glsl

#ifndef COLOURGRADIENT_GLSL
#define COLOURGRADIENT_GLSL
vec4 gradient(vec4 cl1, vec4 cl2, float distance)
{
    return cl1+((cl2-cl1)*distance);
}
#endif // COLOURGRADIENT_GLSL

Gradient.frag

#include <colours/ColourGradient.glsl>
layout(location = 0) in vec2 TexCoords;
layout(location = 0) out vec4 FragColor;

uniform vec4 colourA;
uniform vec4 colourB;
uniform bool colourCentering;
#define MAX_DISTANCE 1.4142135623731 // the square root of 2, basically

void main()
{
    float dist = length(TexCoords) / MAX_DISTANCE;
    if(colourCentering) 
    {
        FragColor = gradient(colourA,colourB,(abs(dist -0.5) * 2.0));
    }
    else FragColor = gradient(colourA,colourB,(diff * dist));
}

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

Мое окончательное намерение состоит в том, чтобы объединить GlSlang и SPIR-V Cross для компиляции Vulkan-совместимого GLSL (расширенного с помощью специального препроцессора C) в SPIR-V и, возможно, обратно в GLSL (или HLSL), если используемый бэкэнд не является Vulkan. Поскольку я не знаю, как соединить несколько двоичных файлов SPIR-V перед декомпиляцией обратно в GLSL, я думаю, что важно иметь только один двоичный файл на шейдерный модуль, поэтому возникает необходимость #include вместо использования нескольких двоичных файлов.

1 ответ

#include директива - не что иное, как вставка кода в точку, поэтому простое сопоставление с "#include <path>" или же "#include "path"должно быть достаточно.

Если необходимы более сложные включения, определения также должны обрабатываться для облегчения защиты (как у вас в коде), но это не обязательно в начале.

Все сказанное, я считаю плохой практикой поддерживать эти дополнения:

  1. Включить не следует использовать для получения доступа к коду в других модулях, поскольку функции уже могут вызываться в других модулях того же типа шейдера. Вы в основном заставляете "полу-подкладку", которая, вероятно, просто приведет к вздутию, а не к повышению скорости.
  2. Определений для использования констант также следует избегать, поскольку они не являются типовыми и контекстно-безопасными. С помощью const float в этом случае было бы намного безопаснее.

В общем, тот факт, что они не существуют, в основном потому, что они не нужны с тщательно разработанным GLSL для начала. Поэтому, прежде чем явно добавлять "функции" к чему-то, что работает, нужно спросить, нужны ли эти дополнения или могут быть достигнуты другими способами.

Другие вопросы по тегам