为什么我的三角形在 Raspberry Pi 上的 OpenGL ES 3 中是白色的

Why is my triangle white in OpenGL ES 3 on Raspberry Pi

我有一个非常简单的 OpenGL ES 程序示例,我试图在 RaspiOS Desktop (a.k.a. Raspbian) 上 运行 在 Raspberry Pi 4.

我的目标很简单——在屏幕中央画一个红色三角形。但是,三角形显示为白色而不是红色。

我已经搜索并尝试了所有方法,但找不到任何帮助。在这一点上,我感到非常沮丧,因为这本应该是介绍 OpenGL ES 世界的第一个教程,但我已经卡住了,无法继续使用更复杂的示例。

无论如何,这是完整的例子

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <stdbool.h>

static struct glData {
    GLuint program;
    GLuint vbo;
} glData;

const char vert_shader_source[] = "#version 300 es                         \n"
                                  "precision mediump float;                \n"
                                  "layout (location = 0) in vec3 Position; \n"
                                  "void main()                             \n"
                                  "{                                       \n"
                                  "   gl_Position = vec4(Position, 1.0);   \n"
                                  "}                                       \n";

const char frag_shader_source[] = "#version 300 es                             \n"
                                  "precision mediump float;                    \n"
                                  "out vec4 fragColor;                         \n"
                                  "void main()                                 \n"
                                  "{                                           \n"
                                  "  fragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f); \n"
                                  "}                                           \n";

#define POSITION 0

bool initWindow(int* argc, char** argv)
{
    glutInit(argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_MULTISAMPLE);
    glutCreateWindow("Triangle");
    GLenum glew_status = glewInit();
    if (glew_status != GLEW_OK) {
        fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status));
        return false;
    }
    return true;
}

static GLuint buildShader(const char* shader_source, GLenum type)
{
    GLuint shader;
    GLint status;

    shader = glCreateShader(type);
    if (shader == 0) {
        return 0;
    }

    glShaderSource(shader, 1, &shader_source, NULL);
    glCompileShader(shader);
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (status != GL_TRUE) {
        int length;
        char* log;

        fprintf(stderr, "failed to compile shader\n");
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
        if (length > 1) {
            log = calloc(length, sizeof(char));
            glGetShaderInfoLog(shader, length, &length, log);
            fprintf(stderr, "%s\n", log);
            free(log);
        }
        return false;
    }

    return true;
}

static GLuint createAndLinkProgram(GLuint v_shader, GLuint f_shader)
{
    GLuint program;
    GLint linked;

    program = glCreateProgram();
    if (program == 0) {
        fprintf(stderr, "failed to create program\n");
        return 0;
    }

    glAttachShader(program, v_shader);
    glAttachShader(program, f_shader);

    glLinkProgram(program);

    glGetProgramiv(program, GL_LINK_STATUS, &linked);

    if (linked != GL_TRUE) {
        int length;
        char* log;

        fprintf(stderr, "failed to link program\n");
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
        if (length > 1) {
            log = calloc(length, sizeof(char));
            glGetProgramInfoLog(program, length, &length, log);
            fprintf(stderr, "%s\n", log);
            free(log);
        }
        glDeleteProgram(program);
        return 0;
    }

    return program;
}

static bool initProgram()
{
    GLuint v_shader, f_shader;

    v_shader = buildShader(vert_shader_source, GL_VERTEX_SHADER);
    if (v_shader == 0) {
        fprintf(stderr, "failed to build vertex shader\n");
        return false;
    }

    f_shader = buildShader(frag_shader_source, GL_FRAGMENT_SHADER);
    if (f_shader == 0) {
        fprintf(stderr, "failed to build fragment shader\n");
        glDeleteShader(v_shader);
        return false;
    }

    glReleaseShaderCompiler(); // should release resources allocated for the compiler

    glData.program = createAndLinkProgram(v_shader, f_shader);
    if (glData.program == 0) {
        fprintf(stderr, "failed to create and link program\n");
        glDeleteShader(v_shader);
        glDeleteShader(f_shader);
        return false;
    }

    glUseProgram(glData.program);

    // this won't actually delete the shaders until the program is closed but it's a good practice
    glDeleteShader(v_shader);
    glDeleteShader(f_shader);

    return true;
}

bool setupOpenGL()
{
    if (!initProgram()) {
        fprintf(stderr, "failed to initialize program\n");
        return false;
    }

    GLfloat vVertices[] = {
        -0.5f, -0.5f, 0.0f,
        0.0f, 0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
    };

    glClearColor(0, 0, 0, 1);
    glGenBuffers(1, &glData.vbo);
    glBindBuffer(GL_ARRAY_BUFFER, glData.vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices), vVertices, GL_STATIC_DRAW);

    return true;
}

void reshape(int width, int height)
{
    glViewport(0, 0, width, height);
}

void drawTriangle()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glEnableVertexAttribArray(POSITION);
    glBindBuffer(GL_ARRAY_BUFFER, glData.vbo);
    glVertexAttribPointer(POSITION, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glDisableVertexAttribArray(POSITION);
    glutSwapBuffers();
}

int main(int argc, char** argv)
{
    printf("initialize window\n");
    if (!initWindow(&argc, argv)) {
        fprintf(stderr, "failed to initialize window\n");
        return EXIT_FAILURE;
    }

    printf("setup opengl\n");
    if (!setupOpenGL()) {
        fprintf(stderr, "failed to setup opengl\n");
        return EXIT_FAILURE;
    }

    glutDisplayFunc(drawTriangle);
    glutReshapeFunc(reshape);
    glutMainLoop();

    glDeleteProgram(glData.program);
    return EXIT_SUCCESS;
}

在你运行它之前,你需要:

  1. 运行 sudo raspi-config
  2. 转到高级选项 > GL 驱动程序
  3. 启用 GL(假 KMS)
  4. 重启

然后你可以像这样运行编译:

gcc triangle.c -Wall -lm -lglut -lGLEW -lGL -o triangle
./triangle

起初我以为可能是驱动程序中的一些错误或其他问题。但后来我发现 this example 并尝试 运行 它并且它绘制了一些具有多种颜色的图形并且它很好。

如果有任何帮助,我将不胜感激。几天来我一直在尝试调试它。

Nvm,原来我是个白痴

这整个时间都是 buildShader() 函数中的一个简单拼写错误。这是该函数的固定版本:

static GLuint buildShader(const char* shader_source, GLenum type)
{
    GLuint shader;
    GLint status;

    shader = glCreateShader(type);
    if (shader == 0) {
        return 0;
    }

    glShaderSource(shader, 1, &shader_source, NULL);
    glCompileShader(shader);
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (status != GL_TRUE) {
        int length;
        char* log;

        fprintf(stderr, "failed to compile shader\n");
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
        if (length > 1) {
            log = calloc(length, sizeof(char));
            glGetShaderInfoLog(shader, length, &length, log);
            fprintf(stderr, "%s\n", log);
            free(log);
        }
        return 0;
    }

    return shader;
}

问题是我不小心返回了 true/false 而不是着色器。我完全不知道程序是如何做到 运行 没有错误并显示一个白色三角形的,但事实就是如此。