在 OpenGL/GLFW 中管理默认着色器
Managing default shaders in OpenGL/GLFW
我正在使用 glfw 编写一个 OpenGL 包装器库,我想将着色器与我的代码一起发布。这些着色器需要在创建 glfw 上下文后进行编译。我想将这些着色器作为 class.
的静态变量
我目前有一个 "DefaultShaders" class 存储静态指针,这些指针在调用 init_shaders() 函数时分配;
DefaultShaders.h
class DefaultShaders {
private:
static const std::string basic_vertex_source;
static const std::string basic_fragment_source;
static const std::string skybox_vertex_source;
static const std::string skybox_fragment_source;
static const std::string framebuffer_vertex_source;
static const std::string framebuffer_fragment_source;
static const ShaderProgram *default_program;
static const ShaderProgram *skybox_program;
static const ShaderProgram *framebuffer_program;
public:
static void init_shaders();
static void delete_shaders();
static const ShaderProgram &get_default_program();
static const ShaderProgram &get_skybox_program();
static const ShaderProgram&get_framebuffer_program();
};
DefaultShaders.cpp
const std::string DefaultShaders::basic_vertex_source = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 tex_coord;\n"
"layout (location = 2) in vec3 aNormal;\n"
"\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"out vec2 TexCoord;\n"
"out vec3 Normal;\n"
"\n"
"void main()\n"
"{\n"
" TexCoord=tex_coord;\n"
" Normal=mat3(transpose(inverse(model))) * aNormal;\n"
" mat4 mvp=projection*view*model;\n"
" gl_Position = mvp*vec4(aPos, 1.0);\n"
"}";
const std::string DefaultShaders::basic_fragment_source = "#version 330 core\n"
"out vec4 FragColor;\n"
"\n"
"in vec2 TexCoord;\n"
"\n"
"uniform sampler2D ourTexture;\n"
"in vec3 Normal;\n"
"\n"
"void main()\n"
"{\n"
" vec3 norm = normalize(Normal);\n"
" vec3 lightDir=vec3(0,1,0);\n"
" float diff = max(dot(norm, lightDir), 0.4);\n"
"\n"
"\n"
" FragColor = texture(ourTexture, TexCoord)*diff;\n"
"}";
const std::string DefaultShaders::skybox_vertex_source = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"\n"
"out vec3 TexCoords;\n"
"\n"
"uniform mat4 pv;\n"
"\n"
"void main()\n"
"{\n"
" TexCoords = aPos;\n"
" vec4 pos=pv * vec4(aPos, 1.0);"
" gl_Position =pos.xyww;\n"
"}";
const std::string DefaultShaders::skybox_fragment_source = "#version 330 core\n"
"out vec4 FragColor;\n"
"\n"
"in vec3 TexCoords;\n"
"\n"
"uniform samplerCube skybox;\n"
"\n"
"void main()\n"
"{ \n"
" FragColor = texture(skybox, TexCoords);\n"
"}";
const std::string DefaultShaders::framebuffer_vertex_source = "#version 330 core\n"
"layout (location = 0) in vec2 aPos;\n"
"layout (location = 1) in vec2 aTexCoords;\n"
"\n"
"out vec2 TexCoords;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); \n"
" TexCoords = aTexCoords;\n"
"} ";
const std::string DefaultShaders::framebuffer_fragment_source = "#version 330 core\n"
"out vec4 FragColor;\n"
" \n"
"in vec2 TexCoords;\n"
"\n"
"uniform sampler2D screenTexture;\n"
"\n"
"void main()\n"
"{ \n"
" FragColor = texture(screenTexture, TexCoords);\n"
"}";
const ShaderProgram *DefaultShaders::default_program;
const ShaderProgram *DefaultShaders::skybox_program;
const ShaderProgram *DefaultShaders::framebuffer_program;
const ShaderProgram &DefaultShaders::get_default_program() {
return *default_program;
}
const ShaderProgram &DefaultShaders::get_skybox_program() {
return *skybox_program;
}
const ShaderProgram &DefaultShaders::get_framebuffer_program() {
return *framebuffer_program;
}
void DefaultShaders::init_shaders() {
VertexShader basic_vertex_shader(basic_vertex_source);
FragmentShader basic_fragment_shader(basic_fragment_source);
VertexShader skybox_vertex_shader(skybox_vertex_source);
FragmentShader skybox_fragment_shader(skybox_fragment_source);
VertexShader framebuffer_vertex_shader(framebuffer_vertex_source);
FragmentShader framebuffer_fragment_shader(framebuffer_fragment_source);
default_program = new ShaderProgram(basic_vertex_shader, basic_fragment_shader);
skybox_program = new ShaderProgram(skybox_vertex_shader, skybox_fragment_shader);
framebuffer_program = new ShaderProgram(framebuffer_vertex_shader, framebuffer_fragment_shader);
}
void DefaultShaders::delete_shaders() {
delete default_program;
delete skybox_program;
delete framebuffer_program;
}
是否有更好的方式将着色器与我的代码一起发布?
正如 HolyBlackCat 所说,原始字符串是在程序中存储字符串的更好方式。如果您仅针对 Windows,则可以使用资源文件来存储着色器。 This guide 应该有帮助。如果您还想为 Mac 和 Linux 编译,您可以像现在一样继续存储着色器(或使用原始字符串只是为了提高可读性)或使用 SPIR-V 着色器。遗憾的是,最后这些在大多数计算机上都不可用,因为它们需要最新的 OpenGL 版本。它们也更难编码,因为它们的级别较低。
我正在使用 glfw 编写一个 OpenGL 包装器库,我想将着色器与我的代码一起发布。这些着色器需要在创建 glfw 上下文后进行编译。我想将这些着色器作为 class.
的静态变量我目前有一个 "DefaultShaders" class 存储静态指针,这些指针在调用 init_shaders() 函数时分配;
DefaultShaders.h
class DefaultShaders {
private:
static const std::string basic_vertex_source;
static const std::string basic_fragment_source;
static const std::string skybox_vertex_source;
static const std::string skybox_fragment_source;
static const std::string framebuffer_vertex_source;
static const std::string framebuffer_fragment_source;
static const ShaderProgram *default_program;
static const ShaderProgram *skybox_program;
static const ShaderProgram *framebuffer_program;
public:
static void init_shaders();
static void delete_shaders();
static const ShaderProgram &get_default_program();
static const ShaderProgram &get_skybox_program();
static const ShaderProgram&get_framebuffer_program();
};
DefaultShaders.cpp
const std::string DefaultShaders::basic_vertex_source = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 tex_coord;\n"
"layout (location = 2) in vec3 aNormal;\n"
"\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"out vec2 TexCoord;\n"
"out vec3 Normal;\n"
"\n"
"void main()\n"
"{\n"
" TexCoord=tex_coord;\n"
" Normal=mat3(transpose(inverse(model))) * aNormal;\n"
" mat4 mvp=projection*view*model;\n"
" gl_Position = mvp*vec4(aPos, 1.0);\n"
"}";
const std::string DefaultShaders::basic_fragment_source = "#version 330 core\n"
"out vec4 FragColor;\n"
"\n"
"in vec2 TexCoord;\n"
"\n"
"uniform sampler2D ourTexture;\n"
"in vec3 Normal;\n"
"\n"
"void main()\n"
"{\n"
" vec3 norm = normalize(Normal);\n"
" vec3 lightDir=vec3(0,1,0);\n"
" float diff = max(dot(norm, lightDir), 0.4);\n"
"\n"
"\n"
" FragColor = texture(ourTexture, TexCoord)*diff;\n"
"}";
const std::string DefaultShaders::skybox_vertex_source = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"\n"
"out vec3 TexCoords;\n"
"\n"
"uniform mat4 pv;\n"
"\n"
"void main()\n"
"{\n"
" TexCoords = aPos;\n"
" vec4 pos=pv * vec4(aPos, 1.0);"
" gl_Position =pos.xyww;\n"
"}";
const std::string DefaultShaders::skybox_fragment_source = "#version 330 core\n"
"out vec4 FragColor;\n"
"\n"
"in vec3 TexCoords;\n"
"\n"
"uniform samplerCube skybox;\n"
"\n"
"void main()\n"
"{ \n"
" FragColor = texture(skybox, TexCoords);\n"
"}";
const std::string DefaultShaders::framebuffer_vertex_source = "#version 330 core\n"
"layout (location = 0) in vec2 aPos;\n"
"layout (location = 1) in vec2 aTexCoords;\n"
"\n"
"out vec2 TexCoords;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); \n"
" TexCoords = aTexCoords;\n"
"} ";
const std::string DefaultShaders::framebuffer_fragment_source = "#version 330 core\n"
"out vec4 FragColor;\n"
" \n"
"in vec2 TexCoords;\n"
"\n"
"uniform sampler2D screenTexture;\n"
"\n"
"void main()\n"
"{ \n"
" FragColor = texture(screenTexture, TexCoords);\n"
"}";
const ShaderProgram *DefaultShaders::default_program;
const ShaderProgram *DefaultShaders::skybox_program;
const ShaderProgram *DefaultShaders::framebuffer_program;
const ShaderProgram &DefaultShaders::get_default_program() {
return *default_program;
}
const ShaderProgram &DefaultShaders::get_skybox_program() {
return *skybox_program;
}
const ShaderProgram &DefaultShaders::get_framebuffer_program() {
return *framebuffer_program;
}
void DefaultShaders::init_shaders() {
VertexShader basic_vertex_shader(basic_vertex_source);
FragmentShader basic_fragment_shader(basic_fragment_source);
VertexShader skybox_vertex_shader(skybox_vertex_source);
FragmentShader skybox_fragment_shader(skybox_fragment_source);
VertexShader framebuffer_vertex_shader(framebuffer_vertex_source);
FragmentShader framebuffer_fragment_shader(framebuffer_fragment_source);
default_program = new ShaderProgram(basic_vertex_shader, basic_fragment_shader);
skybox_program = new ShaderProgram(skybox_vertex_shader, skybox_fragment_shader);
framebuffer_program = new ShaderProgram(framebuffer_vertex_shader, framebuffer_fragment_shader);
}
void DefaultShaders::delete_shaders() {
delete default_program;
delete skybox_program;
delete framebuffer_program;
}
是否有更好的方式将着色器与我的代码一起发布?
正如 HolyBlackCat 所说,原始字符串是在程序中存储字符串的更好方式。如果您仅针对 Windows,则可以使用资源文件来存储着色器。 This guide 应该有帮助。如果您还想为 Mac 和 Linux 编译,您可以像现在一样继续存储着色器(或使用原始字符串只是为了提高可读性)或使用 SPIR-V 着色器。遗憾的是,最后这些在大多数计算机上都不可用,因为它们需要最新的 OpenGL 版本。它们也更难编码,因为它们的级别较低。