顶点着色器如何访问与另一个着色器程序属性绑定的顶点缓冲区数据?

时间:2016-09-29 22:20:18

标签: qt opengl glsl shader vertex-shader

我创建了两个着色器程序shaderProgram0和shaderProgram1。我已将所有相关着色器和变量附加为0或1,以显示它们与shaderProgram0或shaderProgram1的关系。 两个着色器程序都按设计工作。 shaderProgram0使用SimpleVertexShader0.vert作为顶点着色器:

#version 330
in vec3 vertexPosition0;
void main()
{
    gl_Position = vec4(vertexPosition0, 1);
}

shaderProgram0的输出如下:

enter image description here

shaderProgram1使用SimpleVertexShader1.vert作为顶点着色器:

#version 330
in vec3 vertexPosition1;
void main()
{
    gl_Position = vec4(vertexPosition1, 1);
}

shaderProgram1的输出如下:

enter image description here

现在有趣的部分是这个;当使用shaderProgram1时,我不小心评论了顶点属性数组vao1的绑定并留下了未注释的vao0的绑定,导致输出如下图所示,实际上是输出(我认为)只能由shaderProgram0生成!:

enter image description here

简化了代码,使用Windows中的Qt Creator编写代码:

void OpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);

    shaderProgram0.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/SimpleVertexShader0.vert");
    shaderProgram0.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/SimpleFragmentShader0.frag");
    shaderProgram0.link();

    shaderProgram1.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/SimpleVertexShader1.vert");
    shaderProgram1.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/SimpleFragmentShader1.frag");
    shaderProgram1.link();
}

void OpenGLWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
}

void OpenGLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    GLfloat vertexBufferData0[] = {
       -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        0.0f,  1.0f, 0.0f,
    };
    GLuint vbo0;
    glGenBuffers(1, &vbo0);
    glBindBuffer(GL_ARRAY_BUFFER, vbo0);
    glBufferData(GL_ARRAY_BUFFER,
                 sizeof(vertexBufferData0),
                 vertexBufferData0,
                 GL_STATIC_DRAW);
    GLuint vao0;
    glGenVertexArrays(1, &vao0);
    glBindVertexArray(vao0);
    glBindBuffer(GL_ARRAY_BUFFER, vbo0);
    glVertexAttribPointer(glGetAttribLocation(shaderProgram0.programId(),"vertexPosition0"), 3, GL_FLOAT, GL_FALSE, 0, (void*)0);


    GLfloat vertexBufferData1[] = {
       -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        1.0f,  1.0f, 0.0f,
    };
    GLuint vbo1;
    glGenBuffers(1, &vbo1);
    glBindBuffer(GL_ARRAY_BUFFER, vbo1);
    glBufferData(GL_ARRAY_BUFFER,
                 sizeof(vertexBufferData1),
                 vertexBufferData1,
                 GL_STATIC_DRAW);
    GLuint vao1;
    glGenVertexArrays(1, &vao1);
    glBindVertexArray(vao1);
    glBindBuffer(GL_ARRAY_BUFFER, vbo1);
    glVertexAttribPointer(glGetAttribLocation(shaderProgram1.programId(),"vertexPosition1"), 3, GL_FLOAT, GL_FALSE, 0, (void*)0);


    // Now Rendering-----------------------------------------------------
    glBindVertexArray(vao0);
    glEnableVertexAttribArray(glGetAttribLocation(shaderProgram0.programId(),"vertexPosition0"));

//    glBindVertexArray(vao1);
//    glEnableVertexAttribArray(glGetAttribLocation(shaderProgram1.programId(),"vertexPosition1"));

    shaderProgram1.bind();
    glDrawArrays(GL_TRIANGLES, 0, 3);
}

shaderProgram1的顶点着色器访问与shaderProgram0属性绑定的缓冲区数据是不是很奇怪?我认为它不应该生成任何输出,因为没有启用有效的顶点属性数组! 如果有人知道这是如何工作的,请解释这个场景。如果您不明白我的要求那么请仔细查看代码,您将得到重点或我将进一步解释。

修改

// Now Rendering-----------------------------------------------------
glBindVertexArray(vao0);
glEnableVertexAttribArray(glGetAttribLocation(shaderProgram0.programId(),"vertexPosition0"));

shaderProgram0.bind();
glDrawArrays(GL_TRIANGLES, 0, 3);

glBindVertexArray(vao1);
glEnableVertexAttribArray(glGetAttribLocation(shaderProgram1.programId(),"vertexPosition1"));

shaderProgram1.bind();
glDrawArrays(GL_TRIANGLES, 0, 3);

编辑后的代码输出为:

enter image description here

如果两个程序对于唯一的属性使用相同的位置,则会出现一个问题,那么它们应该生成一个或另一个三角形,而不是两个都应该覆盖!? 请跟我说,我刚开始学习它。

1 个答案:

答案 0 :(得分:2)

  

shaderProgram1的顶点着色器访问与shaderProgram0属性绑定的缓冲区数据是不是很奇怪?

没有

如果未在着色器中明确指定属性位置,或在链接程序之前使用glBindAttribLocation,则实现将为您任意分配顶点属性位置。不要求单独的程序使用单独的属性位置。实际上,通常建议您尝试尽可能使程序之间的属性位置接口兼容。

在您的情况下,实施恰好将它们分配到同一位置。因此,任何一个VAO都可以使用这两个程序。