opengl
Shader Chargement et Compilation
Recherche…
Introduction
Ces exemples montrent différentes manières de charger et de compiler des shaders. Tous les exemples doivent inclure un code de gestion des erreurs .
Remarques
Les objets Shader, créés à partir de glCreateShader
ne font pas grand chose. Ils contiennent le code compilé pour une seule étape, mais ils ne doivent même pas contenir le code compilé complet pour cette étape. À bien des égards, ils fonctionnent comme des fichiers objets C et C ++.
Les objets du programme contiennent le programme lié final. Mais ils contiennent également l'état des valeurs uniformes du programme, ainsi qu'un certain nombre d'autres données d'état. Ils ont des API pour l'introspection des données d'interface du shader (même si elles ne sont devenues complètes que dans GL 4.3). Les objets de programme sont ce qui définit le code de shader que vous utilisez lors du rendu.
Les objets Shader, une fois utilisés pour lier un programme, ne sont plus nécessaires à moins que vous ne souhaitiez les utiliser pour lier d'autres programmes.
Charger le shader séparable en C ++
Ce code charge, compile et lie un fichier unique qui crée un programme de shader distinct pour une seule étape . S'il y a des erreurs, il obtiendra le journal d'information pour ces erreurs.
Le code utilise certaines fonctionnalités C ++ 11 couramment disponibles.
#include <string>
#include <fstream>
//In C++17, we could take a `std::filesystem::path` instead of a std::string
//for the filename.
GLuint CreateSeparateProgram(GLenum stage, const std::string &filename)
{
std::ifstream input(filename.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
//Figure out how big the file is.
auto fileSize = input.tellg();
input.seekg(0, ios::beg);
//Read the whole file.
std::string fileData(fileSize);
input.read(&fileData[0], fileSize);
input.close();
//Compile&link the file
auto fileCstr = (const GLchar *)fileData.c_str();
auto program = glCreateShaderProgramv(stage, 1, &fileCstr);
//Check for errors
GLint isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
if(isLinked == GL_FALSE)
{
//Note: maxLength includes the NUL terminator.
GLint maxLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
//C++11 does not permit you to overwrite the NUL terminator,
//even if you are overwriting it with the NUL terminator.
//C++17 does, so you could subtract 1 from the length and skip the `pop_back`.
std::basic_string<GLchar> infoLog(maxLength);
glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
infoLog.pop_back();
//The program is useless now. So delete it.
glDeleteProgram(program);
//Use the infoLog in whatever manner you deem best.
//Exit with failure.
return 0;
}
return program;
}
Compilation d'objet Shader individuel en C ++
Le modèle de compilation GLSL traditionnel consiste à compiler du code pour une scène de shader dans un objet shader, puis à lier plusieurs objets shader (couvrant toutes les étapes que vous souhaitez utiliser) en un seul objet de programme.
Depuis 4.2, il est possible de créer des objets de programme comportant un seul stade de shader. Cette méthode lie toutes les étapes de shader en un seul programme.
Compilation d'objet Shader
#include <string>
#include <fstream>
//In C++17, we could take a `std::filesystem::path` instead of a std::string
//for the filename.
GLuint CreateShaderObject(GLenum stage, const std::string &filename)
{
std::ifstream input(filename.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
//Figure out how big the file is.
auto fileSize = input.tellg();
input.seekg(0, ios::beg);
//Read the whole file.
std::string fileData(fileSize);
input.read(&fileData[0], fileSize);
input.close();
//Create a shader name
auto shader = glCreateShader(stage);
//Send the shader source code to GL
auto fileCstr = (const GLchar *)fileData.c_str();
glShaderSource(shader, 1, &fileCstr, nullptr);
//Compile the shader
glCompileShader(shader);
GLint isCompiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE)
{
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
//C++11 does not permit you to overwrite the NUL terminator,
//even if you are overwriting it with the NUL terminator.
//C++17 does, so you could subtract 1 from the length and skip the `pop_back`.
std::basic_string<GLchar> infoLog(maxLength);
glGetShaderInfoLog(shader, maxLength, &maxLength, &infoLog[0]);
infoLog.pop_back();
//We don't need the shader anymore.
glDeleteShader(shader);
//Use the infoLog as you see fit.
//Exit with failure.
return 0;
}
return shader;
}
Liaison d'objets de programme
#include <string>
GLuint LinkProgramObject(vector<GLuint> shaders)
{
//Get a program object.
auto program = glCreateProgram();
//Attach our shaders to our program
for(auto shader : shaders)
glAttachShader(program, shader);
//Link our program
glLinkProgram(program);
//Note the different functions here: glGetProgram* instead of glGetShader*.
GLint isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked);
if(isLinked == GL_FALSE)
{
GLint maxLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
//C++11 does not permit you to overwrite the NUL terminator,
//even if you are overwriting it with the NUL terminator.
//C++17 does, so you could subtract 1 from the length and skip the `pop_back`.
std::basic_string<GLchar> infoLog(maxLength);
glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
infoLog.pop_back();
//We don't need the program anymore.
glDeleteProgram(program);
//Use the infoLog as you see fit.
//Exit with failure
return 0;
}
//Always detach shaders after a successful link.
for(auto shader : shaders)
gldetachShader(program, shader);
return program;
}