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

我的OpenGL代码为何仅显示黑屏?请求技术排查

OpenGL渲染黑屏问题排查

问题描述

使用C++编写的OpenGL代码,预期渲染两个三角形,但运行后屏幕始终为黑色,本机其他OpenGL代码可正常运行,需排查问题原因。

代码片段

C++主程序代码

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

#include <glm/vec3.hpp> // glm::vec3
#include <glm/vec4.hpp> // glm::vec4
#include <glm/mat4x4.hpp> // glm::mat4
#include <glm/gtc/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective

using namespace std;

static string ParseShader(string filepath) {
    ifstream stream(filepath);
    string line;
    stringstream stringStream;

    while (getline(stream, line))
    {
        stringStream << line << '\n';
    }

    return stringStream.str();
}

static unsigned int CompileShader(unsigned int type, const string& source) {
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str(); // this returns a pointer to data inside the string, the first character
    glShaderSource(id, 1, &src, nullptr); // shader id, count of source codes, a pointer to the array that holds the strings
    glCompileShader(id);

    int result;
    glGetShaderiv(id, GL_COMPILE_STATUS, &result);
    if (result == GL_FALSE) {
        int length;
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        char* message = (char*)alloca(length * sizeof(char));
        glGetShaderInfoLog(id, length, &length, message);
        cout << type << endl;
        cout << message << endl;
        glDeleteShader(id);
        return 0;
    }
    return id;
}

// takes the shader codes as a string parameters 
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader)
{
    GLuint program = glCreateProgram();
    unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
    unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);


    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program); // validate if the program is valid and can be run in the current state of opengl

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

int main(void)
{
    GLFWwindow* window;

    float Angle = 0;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    // call glewInit after creating the context...
    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        /* Problem: glewInit failed, something is seriously wrong. */
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
    }


    GLfloat coordinates[12] = {
        -0.5f,  0.5f,
         0.0f,  0.5f, 
         0.5f,  0.5f, 

        -0.5f,  -0.5f,
         0.0f,  -0.5f,
         0.5f,  -0.5f
    };

    GLuint indices[6] = { 0, 3, 1, 4, 2, 5 };

    GLuint position_buffer;
    glGenBuffers(1, &position_buffer);
    glBindBuffer(GL_ARRAY_BUFFER, position_buffer);
    glBufferData(GL_ARRAY_BUFFER, 6 * 2 * sizeof(float), coordinates, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0); //vertex positions
    glEnableVertexAttribArray(0);


    GLuint index_buffer;
    glGenBuffers(1, &index_buffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLuint), indices, GL_STATIC_DRAW);


    string vertexSource = ParseShader("vertex.shader");
    string fragmentSource = ParseShader("fragment.shader");

    unsigned int program = CreateShader(vertexSource, fragmentSource);
    glUseProgram(program);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        // Render here 
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_INT, nullptr);

         //Swap front and back buffers 
        glfwSwapBuffers(window);

        // Poll for and process events 
        glfwPollEvents();
    }

    glDeleteProgram(program);

    glfwTerminate();
    return 0;
}

顶点着色器(vertex.shader)

#version 330 core 

layout(location = 0) in vec4 position;
layout(location = 1) in vec4 color;

out vec4 var_color;

void main()
{
    var_color = color;
    gl_Position =  position;
};

片段着色器(fragment.shader)

#version 330 core 

out vec4 color;
in vec4 var_color;


void main()
{
    //color = vec4(1.0f, 0.0f, 0.0f, 1.0f);
    color = var_color;
    //discard;
};

问题分析与修复方案

核心问题1:未提供颜色顶点属性数据

顶点着色器声明了layout(location = 1) in vec4 color输入属性,但C++代码仅传递了位置数据,未给颜色属性分配缓冲区或提供有效数据。OpenGL中未初始化的属性值为未定义状态,最终var_color大概率是全黑的默认值,导致片段着色器输出黑色。

核心问题2:绘制模式与索引不匹配

使用GL_TRIANGLE_STRIP模式绘制6个顶点时,当前索引序列{0,3,1,4,2,5}会生成4个三角形(0-3-1、1-3-4、1-4-2、2-4-5),与预期的2个三角形不符。

具体修复步骤

  1. 添加颜色数据并配置顶点属性

    • 修改顶点数据,增加颜色信息:
      GLfloat vertices[] = {
          // 位置          // 颜色
          -0.5f,  0.5f,    1.0f, 0.0f, 0.0f, 1.0f,
           0.0f,  0.5f,    0.0f, 1.0f, 0.0f, 1.0f,
           0.5f,  0.5f,    0.0f, 0.0f, 1.0f, 1.0f,
      
          -0.5f, -0.5f,    1.0f, 1.0f, 0.0f, 1.0f,
           0.0f, -0.5f,    1.0f, 0.0f, 1.0f, 1.0f,
           0.5f, -0.5f,    0.0f, 1.0f, 1.0f, 1.0f
      };
      
    • 更新缓冲区和属性配置:
      glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
      
      // 位置属性(location 0)
      glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
      glEnableVertexAttribArray(0);
      
      // 颜色属性(location 1)
      glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(2 * sizeof(float)));
      glEnableVertexAttribArray(1);
      
  2. 调整绘制模式或索引序列

    • 若要绘制两个三角形,将绘制模式改为GL_TRIANGLES,并调整索引为{0,3,1, 1,3,4}(对应两个三角形的顶点);或保留GL_TRIANGLE_STRIP模式,接受生成4个三角形的结果。
  3. 快速调试验证
    临时修改片段着色器,直接输出固定颜色:

    void main()
    {
        color = vec4(1.0f, 0.0f, 0.0f, 1.0f);
        // color = var_color;
    };
    

    若屏幕显示红色,说明绘制逻辑正常,问题出在颜色属性数据上。

额外建议

  • 在关键API调用后添加glGetError()检查,快速定位OpenGL调用错误;
  • 确认 shader 文件路径正确,确保ParseShader能正常读取文件内容;
  • 检查 shader 编译、链接日志,你的代码已包含日志输出,可根据提示排查 shader 语法问题。

内容的提问来源于stack exchange,提问作者Elen Mouradian

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 05:45:33