opengl
Shader Loading and Compilation
Ricerca…
introduzione
Questi esempi dimostrano vari modi per caricare e compilare shader. Tutti gli esempi devono includere il codice di gestione degli errori .
Osservazioni
Gli oggetti shader, come creati da glCreateShader
, non fanno molto. Essi contengono il codice compilato per un singolo stadio, ma non hanno nemmeno bisogno di contenere il codice completo compilato per quella fase. In molti modi, funzionano come file di oggetti C e C ++.
Gli oggetti del programma contengono il programma finale collegato. Ma mantengono anche lo stato per i valori uniformi del programma, nonché una serie di altri dati di stato. Hanno API per l'introspezione dei dati dell'interfaccia dello shader (sebbene sia diventata completa solo in GL 4.3). Gli oggetti del programma sono ciò che definisce il codice dello shader che si usa durante il rendering.
Gli oggetti shader, una volta utilizzati per collegare un programma, non sono più necessari a meno che non si intenda usarli per collegare altri programmi.
Carica Shader separabile in C ++
Questo codice carica, compila e collega un singolo file che crea un programma shader separato per una singola fase . Se ci sono errori, otterrà il registro delle informazioni per quegli errori.
Il codice utilizza alcune funzionalità C ++ 11 comunemente disponibili.
#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;
}
Compilazione di oggetti shader individuali in C ++
Il modello di compilazione GLSL tradizionale prevede la compilazione del codice per uno stage shader in un oggetto shader, quindi il collegamento di più oggetti shader (che coprono tutti gli stadi che si desidera utilizzare) in un singolo oggetto programma.
Dalla 4.2, è possibile creare oggetti di programma che hanno solo uno stage shader. Questo metodo collega tutte le fasi dello shader in un singolo programma.
Compilazione di oggetti 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;
}
Collegamento dell'oggetto programma
#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;
}