OpenGL/ES 2.0 and Higher: How to Compile Multiple Shader Files Together

╄→гoц情女王★ 提交于 2019-12-25 03:42:56

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!