OpenGL - 无法绘制顶点数组对象和顶点缓冲区对象

时间:2016-06-09 07:07:38

标签: c++ opengl

我在MacOSX 10.10上使用OpenGL和SDL2。我一直在尝试在现代OpenGL中使用VAO和VBO,但我无法让它们绘制。我的着色器非常简单,但根据教程,我一直在努力追随它们应该工作。我没有收到任何错误,但它仍然无法正常工作。我收到的只是一个完全黑色的窗户。如果有人能帮助我了解我的问题所在以及我如何解决它,我将非常感激。我希望我不会重复上一个问题,但我已经搜索过,没有找到解决这个问题的方法。这是我的代码:

vertexShader.glsl:

#version 330 core

layout(location = 0) in vec3 vertexPosition_modelspace;

void main(){
    gl_Position.xyz = vertexPosition_modelspace;
    gl_Position.w = 1.0;
}

fragmentShader.glsl

#version 330 core

out vec4 color;

void main(){
    color = vec4(1.0, 1.0, 0.0, 1.0);
}

这是我加载着色器的代码,它已经工作并且没有提供任何错误:

//Note: PXConsole is a util class for printing to the console.
GLuint loadShaders(std::string vertexPath, std::string fragmentPath){

const char* vertexShaderPath = vertexPath.c_str();
const char* fragmentShaderPath = fragmentPath.c_str();
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

// Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertexShaderPath, std::ios::in);
if(VertexShaderStream.is_open()){
    std::string Line = "";
    while(getline(VertexShaderStream, Line))
        VertexShaderCode += "\n" + Line;
    VertexShaderStream.close();
}else{
    std::string error ="Could not open vertex shader at \"" + vertexPath +"\". Is the the path written correctly? ";
    PXConsole::err(error);
    return 0;
}

// Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(fragmentShaderPath, std::ios::in);
if(FragmentShaderStream.is_open()){
    std::string Line = "";
    while(getline(FragmentShaderStream, Line))
        FragmentShaderCode += "\n" + Line;
    FragmentShaderStream.close();
}else{
    std::string error ="Could not open fragment shader at \"" + fragmentPath +"\". Is the the path written correctly? ";
    PXConsole::err(error);
    return 0;
}

GLint Result = GL_FALSE;
int InfoLogLength;


// Compile Vertex Shader
PXConsole::info("Compiling Vertex Shader at: " + vertexPath);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);

// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
    std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
    glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
    PXConsole::err(&VertexShaderErrorMessage[0]);
}



// Compile Fragment Shader
PXConsole::info("Compiling Fragment Shader at: " + fragmentPath);
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);

// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
    std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
    glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
    PXConsole::err(&FragmentShaderErrorMessage[0]);
}



// Link the program
PXConsole::info("Linking Shader Program!");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);

// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
    std::vector<char> ProgramErrorMessage(InfoLogLength+1);
    glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
    PXConsole::err(&ProgramErrorMessage[0]);
}


glDetachShader(ProgramID, VertexShaderID);
glDetachShader(ProgramID, FragmentShaderID);

glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);

return ProgramID;

这是我用SDL2创建的OpenGL上下文:

SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

appWindow = SDL_CreateWindow("Window Title", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL);

if (!application->appWindow) {
    PXConsole::err("Couldn't Initialize Window!!");
    endApp();
}

appGLContext = SDL_GL_CreateContext(appWindow);

最后这是我的渲染函数循环:

void render(){    

    GLuint vaoID;
    GLuint posVBO;

    GLfloat positions[] = {-0.5f, -0.5f, 1.0f,
        0.5f, -0.5f, 1.0f,
        0.5f, 0.5f, 1.0f,
        -0.5f, 0.5f, 1.0f};


    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //shaderProgramID = the function mentioned above in an initializating function and has no errors finding the shader files

    glUseProgram(shaderProgramID);

    glColor4f(1.0, 1.0, 0.0, 1.0);

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

    glGenBuffers(1, &posVBO);
    glBindBuffer(GL_ARRAY_BUFFER, posVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, posVBO);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glColor4f(1.0, 0.0, 0.0, 1.0);
    glDrawArrays(GL_QUADS, 0, 4);
    glDisableVertexAttribArray(0);

    SDL_GL_SwapWindow(appWindow);
}

我希望有足够的代码来确定问题。谢谢你的帮助!

1 个答案:

答案 0 :(得分:1)

VAO基本上存储由glVertexAttribPointer设置的属性绑定。为了存储它们,必须在VAO绑定时设置它们。在您的情况下,首先解除绑定,然后设置属性绑定。

此外,应该从不在每个帧中生成缓冲区或vaos。这是必须在初始化期间完成的事情。

由于您在问题中说您没有收到任何错误:每个框架中至少有三个错误。你如何检查错误?

  • glColor4f已从OpenGL 3.3 Core Profile中删除。调用此方法应该会导致错误。 (2×)
  • GL_QUADS在核心配置文件中不是有效的drawing mode,也应该生成错误。

更正版本可能如下所示

初始化

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

glGenBuffers(1, &posVBO);
glBindBuffer(GL_ARRAY_BUFFER, posVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

glEnableVertexAttribArray(0);

渲染

glBindVertexArray(vaoID);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

<强>更新

如果要在每个帧中使用新坐标,仍然会生成缓冲区并在初始化中设置VAO。你在每一帧中做的是将新数据上传到缓冲区(假设顶点的数量保持不变):

glBindBuffer(GL_ARRAY_BUFFER, posVBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), positions);

这将覆盖缓冲区的数据而不分配新的GPU内存。请注意,您必须在初始化时使用正确的大小调用glBufferData一次,但使用nullptr作为数据指针来为缓冲区分配内存。