简体   繁体   中英

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

I have a very simple example of a OpenGL ES program that I'm trying to get to run on RaspiOS Desktop (aka Raspbian) on Raspberry Pi 4.

My goal is very simple - to draw a red triangle in the center of the screen. However, the triangle comes out as white instead of red.

I've searched and tried everything and wasn't able to find any help. I'm very frustrated at this point because this was just supposed to be the first tutorial to introduce the world of OpenGL ES and I'm already stuck and can't continue with more complicated examples.

Anyway, here's the full example

#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;
}

Before you run it, you need to:

  1. Run sudo raspi-config
  2. Go to Advanced Options > GL Driver
  3. Enable GL (Fake KMS)
  4. Reboot

Then you can compile and run it like this:

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

At first I thought maybe it's some bug in the driver or something. But then I found this example and tried to run it and it draws some graphs with multiple colors and it's fine.

I'd appreaciate any help. I've been trying to debug this for days now.

Nvm, turns out I'm an idiot.

This entire time it was a simple typo in buildShader() function. Here's the fixed version of that function:

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;
}

The problem was that I was accidentally returning true/false instead of the shader. I have absolutely no idea how the program still managed to run without an error and display a white triangle but that's how it is.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM