glfw 和 glew 不渲染(glDrawElements 与 VAO)

glfw and glew not rendering (glDrawElements with VAO)

我会转储所有信息。我正在使用 C++。无论我尝试什么,glClear() 都有效,而渲染网格则无效。没有错误。

我已经从 freeglut 切换到 glfw。我以前没有问题。我有 glfw3 dll 和 lib,glew 也有。由于未解决的外部问题,我还链接了 OpenGL32 库。

我使用的是 Visual Studio 2017 并且库是最新的。

我从主 glfw 站点获取 glfw 并下载了 64 位二进制文​​件。我从 http://glew.sourceforge.net/ 得到了 glew 32 位和 64 位二进制文​​件。我编译为 64 位和 运行 它在 windows 10 64 位上。

目前可以编译并且 运行s 没有代码错误。

编辑: 我听取了一些建议,但仍然看不到四边形。感谢您的输入。

新代码:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>
#include <string>
#include <iostream>
#include <vector>

GLFWwindow * window;
int width;
int height;

unsigned int vertex_array_buffer;
unsigned int vertex_buffer;
unsigned int index_buffer;

float vertex_model[24] = {
    -0.5f, -0.5f, 0.0f,
    0.0f, 0.0f, 1.0f,

    -0.5f, 0.5f, 0.0f,
    0.0f, 1.0f, 1.0f,

    0.5f, 0.5f, 0.0f,
    1.0f, 1.0f, 1.0f,

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

unsigned int index_model[6] = {
    0, 1, 2,
    0, 2, 3
};

unsigned int program;

float ratio;

int main() {
    if (!glfwInit()) {
        exit(-1);
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    window = glfwCreateWindow(640, 480, "RenderEngine v0.0.0", NULL, NULL);
    if (!window)
    {
        exit(-1);
    }

    glfwMakeContextCurrent(window);

    if (glewInit()) {
        exit(-1);
    }

    glfwSwapInterval(1);

    unsigned int vert_shader;
    unsigned int frag_shader;

    const char * vert_shader_text;
    const char * frag_shader_text;

    std::ifstream file;
    std::string buffer;
    size_t f_size;

    file.open("shader.vert", std::ifstream::in | std::ifstream::binary);

    file.seekg(0, std::ios::end);
    f_size = file.tellg();
    buffer.resize(f_size);
    file.seekg(0);
    file.read(&buffer[0], f_size);
    file.close();

    vert_shader_text = buffer.c_str();

    buffer.clear();

    file.open("shader.frag", std::ifstream::in | std::ifstream::binary);

    file.seekg(0, std::ios::end);
    f_size = file.tellg();
    buffer.resize(f_size);
    file.seekg(0);
    file.read(&buffer[0], f_size);
    file.close();

    frag_shader_text = buffer.c_str();

    vert_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vert_shader, 1, &vert_shader_text, NULL);
    glCompileShader(vert_shader);

    int result = GL_FALSE;
    int log_length;

    glGetShaderiv(vert_shader, GL_COMPILE_STATUS, &result);
    glGetShaderiv(vert_shader, GL_INFO_LOG_LENGTH, &log_length);
    std::vector<char> vert_shader_error((log_length > 1) ? log_length : 1);
    glGetShaderInfoLog(vert_shader, log_length, NULL, &vert_shader_error[0]);
    std::cout << &vert_shader_error[0] << '\n';

    result = GL_FALSE;

    frag_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(frag_shader, 1, &frag_shader_text, NULL);
    glCompileShader(frag_shader);

    glGetShaderiv(frag_shader, GL_COMPILE_STATUS, &result);
    glGetShaderiv(frag_shader, GL_INFO_LOG_LENGTH, &log_length);
    std::vector<char> frag_shader_error((log_length > 1) ? log_length : 1);
    glGetShaderInfoLog(frag_shader, log_length, NULL, &frag_shader_error[0]);
    std::cout << &frag_shader_error[0] << '\n';

    program = glCreateProgram();
    glAttachShader(program, vert_shader);
    glAttachShader(program, frag_shader);

    glBindAttribLocation(program, 0, "pos");
    glBindAttribLocation(program, 1, "color");

    glLinkProgram(program);

    glDeleteShader(vert_shader);
    glDeleteShader(frag_shader);

    glGetProgramiv(program, GL_LINK_STATUS, &result);
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
    std::vector<char> program_error((log_length > 1) ? log_length : 1);
    glGetProgramInfoLog(program, log_length, NULL, &program_error[0]);
    std::cout << &program_error[0] << '\n';

    glUseProgram(program);

    glGenVertexArrays(1, &vertex_array_buffer);
    glBindVertexArray(vertex_array_buffer);
    glGenBuffers(1, &vertex_buffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_model), vertex_model, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float) * 3));
    glGenBuffers(1, &index_buffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(index_model), index_model, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    if (glGetError()) {
        exit(-1);
    }

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

    while (!glfwWindowShouldClose(window))
    {
        glfwGetFramebufferSize(window, &width, &height);
        ratio = width / (float)height;

        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT);

        glBindVertexArray(vertex_array_buffer);

        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);

        glBindVertexArray(0);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwDestroyWindow(window);
    glfwTerminate();

    return 0;
}

如果需要,还有着色器文件。顶点着色器:

#version 330

in layout(location = 0) vec3 pos;
in layout(location = 1) vec3 color;

out vec3 out_color;

void main() {
    gl_Position = vec4(pos, 1.0f);
    out_color = color;
}

片段着色器:

#version 330

in vec3 out_color;

out vec4 final_color;

void main() {
    final_color = vec4(out_color, 1.0f);
}

几个问题:

  • 现在甚至 Intel 也支持 OpenGL 3.3 Core 上下文。请求一:

    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    
  • 实际验证您的着色器 compile/link。在我的系统上,顶点着色器失败并显示:

    Vertex shader failed to compile with the following errors:
    ERROR: 0:3: error(#12) Unexpected qualifier
    ERROR: 0:4: error(#12) Unexpected qualifier
    ERROR: error(#273) 2 compilation errors.  No code generated
    

    layout()应该放在in之前:

    layout(location = 0) in vec3 pos;
    layout(location = 1) in vec3 color;
    
  • 在解除绑定 VAO 后GL_ELEMENT_ARRAY_BUFFER解除绑定。

  • index_model 正在索引 vertex_model 的末尾。不要那样做,除非你喜欢 OpenGL 驱动程序内部的访问冲突:)

截图:


总计:

#include <GL/glew.h>
#include <glfw/glfw3.h>
#include <iostream>
#include <cstdarg>

struct Program
{
    static GLuint Load( const char* shader, ... )
    {
        GLuint prog = glCreateProgram();
        va_list args;
        va_start( args, shader );
        while( shader )
        {
            const GLenum type = va_arg( args, GLenum );
            AttachShader( prog, type, shader );
            shader = va_arg( args, const char* );
        }
        va_end( args );
        glLinkProgram( prog );
        CheckStatus( prog );
        return prog;
    }

private:
    static void CheckStatus( GLuint obj )
    {
        GLint status = GL_FALSE;
        if( glIsShader( obj ) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
        if( glIsProgram( obj ) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
        if( status == GL_TRUE ) return;
        GLchar log[ 1 << 15 ] = { 0 };
        if( glIsShader( obj ) ) glGetShaderInfoLog( obj, sizeof( log ), NULL, log );
        if( glIsProgram( obj ) ) glGetProgramInfoLog( obj, sizeof( log ), NULL, log );
        std::cerr << log << std::endl;
        std::exit( EXIT_FAILURE );
    }

    static void AttachShader( GLuint program, GLenum type, const char* src )
    {
        GLuint shader = glCreateShader( type );
        glShaderSource( shader, 1, &src, NULL );
        glCompileShader( shader );
        CheckStatus( shader );
        glAttachShader( program, shader );
        glDeleteShader( shader );
    }
};

const char* vert = 1 + R"GLSL(
#version 330 core

layout(location = 0) in vec3 pos;
layout(location = 1) in vec3 color;

out vec3 out_color;

void main() {
    gl_Position = vec4(pos, 1.0f);
    out_color = color;
}
)GLSL";

const char* frag = 1 + R"GLSL(
#version 330 core

in vec3 out_color;

out vec4 final_color;

void main() {
    final_color = vec4(out_color, 1.0f);
}
)GLSL";

GLFWwindow * window;
int width;
int height;

unsigned int vertex_array_buffer;
unsigned int vertex_buffer;
unsigned int index_buffer;

float vertex_model[] =
{
    -0.5f, -0.5f, 0.0f,     0.0f, 0.0f, 1.0f,
    -0.5f,  0.5f, 0.0f,     0.0f, 1.0f, 1.0f,
     0.5f,  0.5f, 0.0f,     1.0f, 1.0f, 1.0f,
     0.5f, -0.5f, 0.0f,     1.0f, 0.0f, 1.0f,
};

unsigned int index_model[] =
{
    0, 1, 2,
};

unsigned int program;

float ratio;

int main()
{
    if( !glfwInit() )
    {
        exit( -1 );
    }

    glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
    glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
    glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
    window = glfwCreateWindow( 640, 480, "RenderEngine v0.0.0", NULL, NULL );
    if( !window )
    {
        exit( -1 );
    }

    glfwMakeContextCurrent( window );

    if( glewInit() )
    {
        exit( -1 );
    }

    glfwSwapInterval( 1 );

    GLuint program = Program::Load( vert, GL_VERTEX_SHADER, frag, GL_FRAGMENT_SHADER, NULL );
    glUseProgram( program );

    glGenVertexArrays( 1, &vertex_array_buffer );
    glBindVertexArray( vertex_array_buffer );

    glGenBuffers( 1, &vertex_buffer );
    glBindBuffer( GL_ARRAY_BUFFER, vertex_buffer );
    glBufferData( GL_ARRAY_BUFFER, sizeof( vertex_model ), vertex_model, GL_STATIC_DRAW );
    glEnableVertexAttribArray( 0 );
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof( float ) * 6, (void*)0 );
    glEnableVertexAttribArray( 1 );
    glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, sizeof( float ) * 6, (void*)( sizeof( float ) * 3 ) );
    glBindBuffer( GL_ARRAY_BUFFER, 0 );

    glGenBuffers( 1, &index_buffer );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, index_buffer );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( index_model ), index_model, GL_STATIC_DRAW );

    glBindVertexArray( 0 );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );

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

    while( !glfwWindowShouldClose( window ) )
    {
        glfwGetFramebufferSize( window, &width, &height );
        ratio = width / (float)height;

        glViewport( 0, 0, width, height );
        glClear( GL_COLOR_BUFFER_BIT );

        glBindVertexArray( vertex_array_buffer );
        glDrawElements( GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr );
        glBindVertexArray( 0 );

        glfwSwapBuffers( window );
        glfwPollEvents();
    }

    glfwDestroyWindow( window );
    glfwTerminate();

    return 0;
}

glVertexAttribPointer 获取传递的参数和当前绑定的 VBO 并将该信息保存在 当前 绑定的 VAO 的状态中。

glEnableVertexAttribArray 也仅在 当前 绑定的 VAO 中启用一个属性。你太早启用它们了。

所以,正确的做事顺序是:

  1. 绑定 VAO
  2. 绑定 VBO
  3. 调用 glVertexAttribPointerglEnableVertexAttribArray
  4. 现在你可以解绑VBO或者重复2-3因为3.保存了状态到VAO
  5. 解绑 VAO

索引缓冲区应放置在 1-5 之间的任何位置。请注意不要意外地过早解除索引缓冲区的绑定——此时 VAO 仍处于绑定状态。因为 VAO 只记住一个索引缓冲区。

除了早期的调用,我没有发现任何错误。

通过将 glVertexAttribPointer 的功能拆分为 glVertexArrayAttribBindingglVertexArrayAttribFormat 和 [=17],此 "hidden" VBO 捕获已在 OpenGL 4.5 中 "revealed" =].

名为 index buffer object is a state of the vertex array objects 的状态向量。 如果你这样做glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0),当顶点数组对象被绑定时,那么对元素缓冲区的引用就被破坏了。

删除glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);,解决问题:

glGenVertexArrays(1, &vertex_array_buffer);
glBindVertexArray(vertex_array_buffer);

// [...]

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);

// [...]

//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // <---- skip this
glBindVertexArray(0);

顶点数组中有4个坐标和颜色属性,所以索引必须在[0, 3]范围内。坐标排列成四边形,四边形可以由2个三角形绘制如下:

1         2
 +-------+
 |     / |
 |   /   |
 | /     |
 +-------+
0         3
unsigned int index_model[6] = {
    0, 1, 2,
    0, 2, 3
};