#include с пользовательским вводом-выводом для GLSL/C?
У меня два вопроса, два очень важных:
- Существует ли препроцессор C, который сможет использовать любую пользовательскую функцию для поиска файла, вызываемого
#include
? Потому что, скажем, мои коды хранятся в ZIP-файле или где-то еще, и я полагаюсь на PhysFS, чтобы получить к ним доступ, а не разархивировать их. Существует ли препроцессор C с открытым исходным кодом, который может работать с этим, вместо того, чтобы ограничиваться обычным fopen? - Можно ли использовать собственный или стандартный препроцессор C в коде GLSL? Я знаю, что у GLSL уже есть препроцессор, но ему не хватает
#include
особенность, и я хочу исправить это. - Можно ли объединить два вышеперечисленных, чтобы иметь программу или видеоигру, где исходные коды GLSL хранятся в файле ZIP или PK3 (следовательно, доступ к нему осуществляется с помощью PhysFS или любой другой вещи ввода-вывода), а пользовательский / модифицированный препроцессор C - это используется для обработки #include и получения включенных источников?
Я спрашиваю об этом, потому что у меня нет желания писать свой собственный препроцессор C для GLSL, если это не является абсолютно необходимым, и предпочел бы использовать существующий для реализации #include с пользовательским вводом-выводом.
Практически единственная причина, по которой мне нужен препроцессор C, это то, что я хочу #include
и я хочу это с моей собственной вещью ввода-вывода.
Примеры функций препроцессора, которые я хотел бы реализовать:
- Предварительно весь уже обработанный исходный код
#version 450
, или же#version 310 es
, так же как#extension GL_ARB_separate_shader_objects : enable
- Включая константы времени выполнения. Некоторые говорят, что униформа может быть лучше для этой цели, но заранее определенные неоднозначные константы, вероятно, тоже подойдут.
- Повторное использование функций.
Один пример предполагаемого использования:
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"
должно быть достаточно.
Если необходимы более сложные включения, определения также должны обрабатываться для облегчения защиты (как у вас в коде), но это не обязательно в начале.
Все сказанное, я считаю плохой практикой поддерживать эти дополнения:
- Включить не следует использовать для получения доступа к коду в других модулях, поскольку функции уже могут вызываться в других модулях того же типа шейдера. Вы в основном заставляете "полу-подкладку", которая, вероятно, просто приведет к вздутию, а не к повышению скорости.
- Определений для использования констант также следует избегать, поскольку они не являются типовыми и контекстно-безопасными. С помощью
const float
в этом случае было бы намного безопаснее.
В общем, тот факт, что они не существуют, в основном потому, что они не нужны с тщательно разработанным GLSL для начала. Поэтому, прежде чем явно добавлять "функции" к чему-то, что работает, нужно спросить, нужны ли эти дополнения или могут быть достигнуты другими способами.