GLSL片段着色器未修改输出颜色:编译正常但窗口未显红色
问题排查与解决
核心原因
- OpenGL Core Profile 限制:你使用的是OpenGL 3.1 Core Profile,该模式彻底移除了固定功能管线。这意味着仅绑定片段着色器无法产生任何输出——必须搭配顶点着色器,并且主动触发绘制操作。
- 缺少绘制操作:当前代码仅执行了
glClear清除屏幕,没有调用任何绘制函数(如glDrawArrays),GPU从未执行片段着色器,因此始终显示清屏颜色。
解决方案
需要补充顶点着色器、创建顶点数组对象(VAO,Core Profile强制要求),并调用绘制函数触发着色器执行。以下是具体修改步骤:
1. 添加适配的顶点着色器
使用全屏三角形方案(无需顶点缓冲区,直接在着色器中生成顶点),覆盖整个标准化设备坐标(NDC)空间:
const char *vert_shader_src = R"GLSL( #version 140 void main() { // 定义全屏三角形的三个顶点,覆盖整个屏幕 vec2 vertices[3] = vec2[]( vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0) ); gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0); } )GLSL";
2. 编译并链接顶点着色器
取消顶点着色器的注释,编译后与片段着色器一起链接到程序:
GLuint vert_shader = compile_shader(vert_shader_src, GL_VERTEX_SHADER); GLuint program = link_program(vert_shader, frag_shader);
3. 创建并绑定VAO
Core Profile要求任何绘制操作必须绑定VAO,即使没有顶点缓冲区:
GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao);
4. 触发绘制操作
在主循环的glClear之后添加绘制函数,执行全屏三角形的绘制:
glDrawArrays(GL_TRIANGLES, 0, 3);
修改后的完整代码
#include <iostream> #include <GL/glew.h> #include <SDL2/SDL.h> #include <SDL2/SDL_opengl.h> GLuint compile_shader(const char *shader, GLenum type) { GLuint shader_id = glCreateShader(type); glShaderSource(shader_id, 1, &shader, NULL); glCompileShader(shader_id); GLint compiled; glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compiled); if (!compiled) { int length; glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &length); char* message = new char[length]; glGetShaderInfoLog(shader_id, length, &length, message); std::cerr << "Error compiling shader: " << message << std::endl;; delete[] message; glDeleteShader(shader_id); return 0; } return shader_id; } GLuint link_program(GLuint vertex_shader, GLuint frag_shader) { GLuint program = glCreateProgram(); if (vertex_shader != 0) glAttachShader(program, vertex_shader); if (frag_shader != 0) glAttachShader(program, frag_shader); glLinkProgram(program); GLint linked; glGetProgramiv(program, GL_LINK_STATUS, &linked); if (!linked) { int length; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); char* message = new char[length]; glGetProgramInfoLog(program, length, &length, message); std::cerr << "Error linking program: " << message << std::endl; delete[] message; glDetachShader(program, vertex_shader); glDetachShader(program, frag_shader); glDeleteProgram(program); return 0; } return program; } int main(void) { SDL_Init(SDL_INIT_VIDEO); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_Window *window = SDL_CreateWindow("Title", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL); SDL_GLContext context = SDL_GL_CreateContext(window); (void) context; glewInit(); const char *vert_shader_src = R"GLSL( #version 140 void main() { vec2 vertices[3] = vec2[]( vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0) ); gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0); } )GLSL"; const char *frag_shader_src = R"GLSL( #version 140 void main() { gl_FragColor = vec4(1, 0, 0, 1); } )GLSL"; glClearColor(.0f, .3f, .7f, 1.f); GLuint vert_shader = compile_shader(vert_shader_src, GL_VERTEX_SHADER); GLuint frag_shader = compile_shader(frag_shader_src, GL_FRAGMENT_SHADER); GLuint program = link_program(vert_shader, frag_shader); // 创建并绑定VAO GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); SDL_Event event; int quit = 0; glUseProgram(program); while (!quit) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 绘制全屏三角形 glDrawArrays(GL_TRIANGLES, 0, 3); while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: quit = 1; break; } } SDL_GL_SwapWindow(window); } // 清理资源 glDeleteVertexArrays(1, &vao); glDeleteShader(vert_shader); glDeleteShader(frag_shader); glDeleteProgram(program); SDL_DestroyWindow(window); SDL_Quit(); return 0; }
额外说明
- 全屏三角形通过三个顶点覆盖整个NDC空间,相比矩形(四个顶点)更高效,且无需额外的顶点缓冲区数据。
- 同步了GLSL版本为140(与OpenGL 3.1对应),避免版本不匹配问题。
- 补充了程序链接日志的获取,便于排查潜在的链接警告或错误。
内容的提问来源于stack exchange,提问作者Basil
相关产品推荐
相关产品推荐

