Обычно шейдеры хранят в отдельных файлах (*.frag, *.vert и пр.) - так несколько шейдерных программ можно составить из различных комбинаций шейдеров. Однако на практике все всё равно пишут отдельные шейдеры для каждой отдельной программы, даже если коды иногда дублируются - никому путаница не нужна. Проще хранить коды всех шейдеров программы в одном файле. Для этого я придумал формат файла "*.glsl" - на каждую шейдерную программу один файл с кодами всех её шейдеров. Он позволяет хранить коды вершинных, обоих тесселяционных, геометрических и фрагментных шейдеров в одном файле (разумеется, все типы шейдеров не обязательно пихать).
Для поддержки файлов формата .glsl включите в Ваш проект этот заголовочный файл:
Требует LoadGL.h.
В файлах формата .glsl коды для отдельных шейдеров разделяются с помощью "тэгов" - названий шейдеров в квадратных скобках:
[GL_VERTEX_SHADER] [GL_FRAGMENT_SHADER] [GL_GEOMETRY_SHADER] [GL_TESS_CONTROL_SHADER] [GL_TESS_EVALUATION_SHADER]
Строки кода, идущие от начала файла и ДО первого тэга (или после пустого тэга []) дублируются для всех шейдеров - это удобно для указания версии, общих констант, функций или униформ, а также для объявления интерфейсных переменных (в старых GLSL версиях). Строки кода после тэга относятся к тому шейдеру, чей идентификатор был указан в вышележащем тэге. Один и тот же тэг может быть использован несколько раз (хотя я хз зачем так делать, но всё же).
В строке с тэгом не должно быть никаких табов, пробелов и других символов.
Создаются ТОЛЬКО те шейдеры, для которых есть индивидуальный код. Т.е. если тэг присутствует, но после него лишь пустые строки да комменты (которые, кстати, вырезаются), то шейдер создан не будет (даже если присутствует общий для всех шейдеров код).
В файле FileGLSL.hpp всего две функции: CreateShader (загрузка кода указанного шейдера напрямую) и LoadGLSL (загрузка кодов шейдеров из *.glsl файла).
GLuint CreateShader(GLenum ShaderType, const char* ShaderCode);
Функция создаёт шейдер указанного типа, загружает его код, компиллирует шейдер (при ошибке выводится окно с проблемным кодом и руганью компиллятора), после чего возвращает идентификатор шейдерного объекта (или 0 в случае ошибки).
ShaderType - одна из OpenGL констант, идентифицирующая тип графического шейдера: GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER или GL_TESS_EVALUATION_SHADER.
ShaderCode - код шейдера в формате NULL-terminated string. Отдельные строчки кода в ней разделяются символами новой строки.
GLuint LoadGLSL(const char* FileName);
Создаёт шейдерную программу из исходников, находящихся в указанном файле (FileName), после чего возвращает идентификатор объекта шейдерной программы (или 0 в случае ошибки). Функция LoadGLSL использует CreateShader, поэтому в случае ошибки при компилляции вылезет окно с дебаговой информацией. Обнаружение ошибок при компилляции шейдеров или линковке программы вызовет попап-окно, предлагающее закрыть приложение, проигнорировать ошибку или исправить файл и попробовать скомпилировать всё снова.
Пример содержимого *.glsl файла:
//Common for all shaders: varying vec4 Color; [GL_VERTEX_SHADER] //Vertex shader code: void main() { Color = gl_Color; gl_Position = ftransform(); } [GL_GEOMETRY_SHADER] //We do not use geometry shader [GL_FRAGMENT_SHADER] //This uniform is used only in fragment shader: uniform sampler2D Texture; //Fragment shader code: void main() { gl_FragColor = Color; }
В результате будет создана программа, состоящая из вершинного и фрагментного шейдера (у шейдера геометрии нет строк своего кода):
загруженный код вершинного шейдера:
varying vec4 Color; void main() { Color = gl_Color; gl_Position = ftransform(); }
загруженный код фрагментного шейдера:
varying vec4 Color; uniform sampler2D Texture; void main() { gl_FragColor = Color; }