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

问题描述

我有一个非常简单的 OpenGL ES 程序示例,我试图在 RaspBerry Pi 4 上的 RaspiOS 桌面(又名 Raspbian)上运行该程序。

我的目标非常简单 - 在屏幕中央绘制一个红色三角形。但是,三角形显示为白色而不是红色。

我已经搜索并尝试了所有方法,但找不到任何帮助。在这一点上,我非常沮丧,因为这应该是介绍 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,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,sizeof(char));
            glGetProgramInfoLog(program,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.5f,};

    glClearColor(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,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);
    glDrawArrays(GL_TRIANGLES,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 而不是着色器。我完全不知道该程序如何仍然能够无错误地运行并显示一个白色三角形,但事实就是这样。