You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GLSL片段着色器未修改输出颜色:编译正常但窗口未显红色

问题排查与解决

核心原因

  1. OpenGL Core Profile 限制:你使用的是OpenGL 3.1 Core Profile,该模式彻底移除了固定功能管线。这意味着仅绑定片段着色器无法产生任何输出——必须搭配顶点着色器,并且主动触发绘制操作。
  2. 缺少绘制操作:当前代码仅执行了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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 10:57:35