使用顶点缓冲区对象在OpenGL中进行基本线渲染

时间:2014-08-29 03:07:41

标签: c opengl

我有点跟随this OpenGL example,我的代码会编译,但它无法正常工作。

我希望看到一个白色的矩形,但是没有任何东西可以渲染但是颜色清晰。致电glDrawArrays后,glGetError告诉我错误1282已被提出。我确定这个问题非常明显,但我无法看到我出错的地方。这是我的问题的简单例子:

#include <errno.h>
#include <stdio.h>

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

#define WINDOW_W 300
#define WINDOW_H 300

static const GLchar *vertex_shader_src = {
    "#version 440\n"
    "in vec4 position;\n"
    "uniform mat4 projection;\n"
    "void main()\n"
    "{\n"
        "\tgl_Position = projection * position;\n"
    "}\n"
};

static const GLchar *fragment_shader_src = {
    "#version 440\n"
    "uniform vec4 color;\n"
    "out vec4 outputColor;\n"
    "void main()\n"
    "{\n"
        "outputColor = color;\n"
    "}\n"
};

static GLuint program = 0;

static GLuint vao = 0;

static const GLfloat rect_vertices[] = {
    5.0f, 5.0f,
    WINDOW_W - 5.0f, 5.0f,

    WINDOW_W - 5.0f, 5.0f,
    WINDOW_W - 5.0f, WINDOW_H - 5.0f,

    WINDOW_W - 5.0f, WINDOW_H - 5.0f,
    5.0f, WINDOW_H - 5.0f,

    5.0f, WINDOW_H - 5.0f,
    5.0f, 5.0f
};

static GLuint rect_vbo = 0;

int init_program()
{
    GLint status;
    GLuint vertexShader;
    GLuint fragmentShader;

    // Initialize our vertex shader.

    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertex_shader_src, NULL);
    glCompileShader(vertexShader);

    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);

    if(status == GL_FALSE)
        return -EINVAL;

    // Initialize our fragment shader.

    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragment_shader_src, NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);

    if(status == GL_FALSE)
        return -EINVAL;

    // Initialize the program.

    program = glCreateProgram();

    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);

    glLinkProgram(program);

    glGetProgramiv(program, GL_LINK_STATUS, &status);

    if(status == GL_FALSE)
        return -EINVAL;

    // Detach the shaders, now that the program is linked.

    glDetachShader(program, vertexShader);
    glDetachShader(program, fragmentShader);

    // Done!

    return 0;
}

void ortho_matrix(GLfloat *m, GLfloat l, GLfloat r,
    GLfloat b, GLfloat t, GLfloat n, GLfloat f)
{
    m[0] = 2.0f / (r - l);
    m[1] = 0.0f;
    m[2] = 0.0f;
    m[3] = 0.0f;

    m[4] = 0.0f;
    m[5] = 2.0f / (t - b);
    m[6] = 0.0f;
    m[7] = 0.0f;

    m[8] = 0.0f;
    m[9] = 0.0f;
    m[10] = -2.0f / (f - n);
    m[11] = 0.0f;

    m[12] = 0.0f;
    m[13] = 0.0f;
    m[14] = 0.0f;
    m[15] = 1.0f;
}

int gl_color(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
    GLint colorVec;
    GLfloat color[4] = {r, g, b, a};

    colorVec = glGetUniformLocation(program, "color");

    if(colorVec == -1)
        return -EINVAL;

    glUniform4fv(colorVec, 1, color);

    return 0;
}

int set_uniforms(int width, int height)
{
    int r;
    GLint orthoMatrix;
    GLfloat matrix[16];

    // Set our orthographic projection uniform.

    orthoMatrix = glGetUniformLocation(program, "projection");

    if(orthoMatrix == -1)
        return -EINVAL;

    ortho_matrix(matrix, -0.5f, ((GLfloat) (width - 1)) + 0.5f,
        ((GLfloat) (height - 1)) + 0.5f, -0.5f, 0.0f, 1.0f);

    glUniformMatrix4fv(orthoMatrix, 1, GL_FALSE, matrix);

    // Set our rendering color uniform.

    r = gl_color(1.0f, 1.0f, 1.0f, 1.0f);

    if(r < 0)
        return r;

    // Done!

    return 0;
}

int init_vbo()
{
    glGenBuffers(1, &rect_vbo);

    glBindBuffer(GL_ARRAY_BUFFER, rect_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(rect_vertices),
        rect_vertices, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    return 0;
}

int render()
{
    GLenum err;

    glBindBuffer(GL_ARRAY_BUFFER, rect_vbo);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glDrawArrays(GL_LINES, 0, sizeof(rect_vertices) / sizeof(GLfloat));

err = glGetError();

while(err != GL_NO_ERROR)
{
    printf("glDrawArrays err: %d\n", err);
    err = glGetError();
}

    glDisableVertexAttribArray(0);

    return 0;
}

int main(void)
{
    int r;
    GLFWwindow *window;

    int width;
    int height;

    if(!glfwInit())
        return -EINVAL;

    window = glfwCreateWindow(WINDOW_W, WINDOW_H,
        "My Window", NULL, NULL);

    if(!window)
    {
        glfwTerminate();
        return 1;
    }

    glfwMakeContextCurrent(window);

    r = init_program();

    if(r < 0)
    {
        glfwTerminate();
        return 1;
    }

    r = init_vbo();

    if(r < 0)
    {
        glfwTerminate();
        return 1;
    }

    while(!glfwWindowShouldClose(window))
    {
        // Initialize the GL viewport.

        glfwGetFramebufferSize(window, &width, &height);

        r = set_uniforms(width, height);

        if(r < 0)
        {
            glfwTerminate();
            return r;
        }

        glViewport(0, 0, width, height);

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(program);

        // Call the user-provided rendering function.

        r = render();

        if(r < 0)
        {
            glfwTerminate();
            return r;
        }

        // End GL rendering, swap the buffer, and poll for events.

        glUseProgram(0);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();

    return 0;
}

我已尝试搜索此错误编号,并且我已找到例如this,但我真的没有办法找出具体出错的地方。

我做错了什么,或者,我怎么能找到?

2 个答案:

答案 0 :(得分:1)

我看到的唯一明显问题是glDrawArrays()的参数:

glDrawArrays(GL_LINES, 0, sizeof(rect_vertices) / sizeof(GLfloat));

第三个参数是顶点数,而此处传递的值是浮点值的数量。由于此代码中的顶点每个顶点使用2个浮点坐标,因此应为:

glDrawArrays(GL_LINES, 0, sizeof(rect_vertices) / (2 * sizeof(GLfloat)));

在理想的世界中,您会在the official man page的错误部分中查找可能的错误。不幸的事实是,手册页通常是不完整的,特别是在错误条件方面。所以这是一个很好的起点,但并不总是最后一句话。

如果手册页看起来有问题,要了解事情的底部,有spec文档。我确实看过那里,而且坦率地说我还不完全清楚究竟是什么导致了你GL_INVALID_OPERATION。我在这里找到了一位候选人:

  

如果命令将数据源超出缓冲区对象的末尾,则会生成INVALID_OPERATION错误。

但这实际上属于glDrawArraysInstanced(),因此我不清楚它是否也适用于glDrawArrays()

另一个选择是你有一个核心配置文件上下文。但是你没有要求,而且根据我对GLFW文档的理解,它不是默认的。在Core Profile中,您必须使用VAO(顶点数组对象)来设置顶点状态。

答案 1 :(得分:0)

我实际上发现了什么是错的。这个错误实际上发生得比我原先想象的要早得多,我在那里设置制服。 This page得到了答案 - 特别是:

  

glUniform不起作用

     

您可能没有先绑定正确的着色器。首先调用glUseProgram(myprogram)。

将我的号码转移到set_uniforms以下,我的号码glUseProgram下方允许渲染正常工作。