C++ OpenGL/ES 2.0及更高版本:如何一起编译多个着色器文件

C++ OpenGL/ES 2.0及更高版本:如何一起编译多个着色器文件,c++,opengl,glsl,qt5,C++,Opengl,Glsl,Qt5,这个问题以不同的方式被问了多次。我的问题是针对OpenGL 2.0/GLSL 1.10及更高版本,以及与OpenGL ES 2.0及其支持的GLSL版本的潜在兼容性: 建议使用哪些C/C++API将多个文件合并到一个着色器源中以传递到 例如,如果我有3个文件A.frag、B.frag、C.frag,它们具有以下内容: /* A.frag */ struct A { vec3 val; }; /* B.frag */ struct B { vec3 val; }; /* C.f

这个问题以不同的方式被问了多次。我的问题是针对OpenGL 2.0/GLSL 1.10及更高版本,以及与OpenGL ES 2.0及其支持的GLSL版本的潜在兼容性:

建议使用哪些C/C++API将多个文件合并到一个着色器源中以传递到

例如,如果我有3个文件A.frag、B.frag、C.frag,它们具有以下内容:

/* 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);
}

有什么现有的工具可以让我将所有三个文件的内容合并到一个源代码中,以便对其进行编译?考虑到每个着色器源可能要复杂得多。

如果查看函数规范glShaderSource:

您可以看到第三个参数是字符串字符数组的数组

我编写了C++类来实现你想要做的事情。我发现最好的方法是分别加载文件,然后将不同的着色器源代码放入双指针,最后将其传递给函数glShaderSource

例如:

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);
}
这不是很简单,不幸的是OpenGL仍然是用纯C编写的。不过,您可以找到实现整个类的要点。通过这样做,您可以编译和链接多个着色器,只要它们都属于同一类型


希望能有所帮助。

您可能想看看,我本来打算做一些类似的事情,但我的开发人员告诉我,必须有一个已经存在的API来为您实现这一点。
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);
}