问题
This question has been asked multiple times in different ways. My question is specific to OpenGL 2.0 / GLSL 1.10 and higher and potential compatibility with OpenGL ES 2.0 and its supported version of GLSL:
What are recommended C/C++ APIs used to combine multiple files into one shader source to pass into glShaderSource.
For example, if I have 3 files A.frag, B.frag, C.frag that have the following contents:
/* A.frag */
struct A
{
vec3 val;
};
/* B.frag */
struct B
{
vec3 val;
};
/* C.frag */
void main() {
struct A a;
a.val = vec3(1.0, 1.0, 1.0);
struct B b;
b.val = vec3(1.0, 1.0, 1.0);
float f = dot(a.val, b.val);
}
What already existing tools would allow me to combine all three file's contents into one source so it could be compiled? Take into consideration that each shader source could be far more complex.
回答1:
If you look at the function specification glShaderSource
:
void glShaderSource(GLuint shader,
GLsizei count,
const GLchar **string,
const GLint *length);
You see that the third parameter is an array of array of string (chars).
I wrote a c++ class to achieve what you are trying to do. The best approach I found is to load the files separately and then put in a double pointer the different shader source codes and then finally pass it to the function glShaderSource.
For example:
GLchar** fragment_code; // This must be initialized
GLint* fragment_char_count;
void LoadFragment()
{
//assuming fragment_filepath a vector<string> containing different shader filepaths
for (size_t i = 0; i < fragment_filepath.size(); i++)
{
Load(fragment_filepath[i], fragment_code[i], fragment_char_count[i]);
}
}
// source_path is the shader file path in the filesystem
// output will contain the source code of the shader being loaded
// fragment_char_count will contain the number of char for the shader being loaded
static void Load(string source_path, GLchar*& output,GLint& fragment_char_count)
{
string return_code;
try
{
// Open files
ifstream vShaderFile(source_path);
stringstream vShaderStream;
// Read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
// Convert stream into GLchar array
return_code = vShaderStream.str();
}
catch(exception e)
{
cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ: " << source_path << endl;
}
fragment_char_count = return_code.length() ;
output = new GLchar[count + 1];
std::size_t length = return_code.copy(output,fragment_char_count,0);
output[length]= '\0';
}
// eventually when you compile you pass to glShaderSource the fragment_id, the number of shader program you are loading (fragment_filepath.size()), the double pointer of char containing the different source codes (fragment_code) and an array representing the char count for each source (fragment_char_count)
void CompileFragment()
{
glShaderSource(fragment_shader_id, fragment_filepath.size(), fragment_code, fragment_char_count);
glCompileShader(d_vertex_shader);
}
It's not very straightforward, unfortunately OpenGL is still written in plain C. However Here you can find a gist with the whole class implemented. By doing so you can compile and link several shaders all together (as long as they are all of the same type of course).
hope it helps.
来源:https://stackoverflow.com/questions/29243942/opengl-es-2-0-and-higher-how-to-compile-multiple-shader-files-together