【问题标题】:How the vertex shader access the vertex buffer data bound with another shaderprogram attribute?顶点着色器如何访问与另一个着色程序属性绑定的顶点缓冲区数据?
【发布时间】:2016-09-29 22:20:18
【问题描述】:

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

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

shaderProgram0的输出是这样的:

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

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

shaderProgram1的输出是这样的:

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

代码经过简化,是在 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);

编辑后的代码输出为:

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

【问题讨论】:

  • 当前绑定的程序完全独立于存储在VAO中的管道输入配置。如果当前绑定的 VAO 从某些缓冲区获取数据到某些属性中。您可以不断更改程序并仍然从相同的输入为管道提供数据,这看起来就像您正在(不小心?)在做的事情。
  • 另请注意,启用顶点属性是 VAO 的设置,而不是程序的设置。 VAO 和程序“相遇”的地方是在建立这些属性的位置时,这是您没有在代码中明确执行的操作——在您的系统上,偶然地,两个程序都使用相同的位置唯一的属性,因此它们都可以使用相同的 VAO。
  • @peppe 我已经编辑了我的问题,你能看一下吗?你的回答很有道理,但我想消除我的疑虑。

标签: qt opengl glsl shader vertex-shader


【解决方案1】:

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

没有。

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

在您的情况下,实施碰巧将它们分配到同一个位置。所以任何一个 VAO 都可以与任何一个程序一起工作。

【讨论】:

  • @ShujaatAliKhan:……你的编辑特别怎么样?根据之前的工作方式,这种行为没有什么令人惊讶或意外的。
  • 我不明白的是,每个着色器程序都有不同的 id,glDrawArrays 在启用的 VAO 上工作,所以当我像这样启用 shaderProgram0 的属性时:glEnableVertexAttribArray(glGetAttribLocation(shaderProgram0.programId() “顶点位置0”));那么shaderProgram1如何访问为shaderProgram0初始化的数据块呢?我知道我想问什么,但由于我较少接触opengl相关术语,我无法将我的想法转化为文字:'(
  • @ShujaatAliKhan:因为,正如我所说,顶点属性位置不是程序特定的。或者更确切地说,它们不是程序唯一。单独的程序可以并且经常使用相同的属性位置。
  • 请你看看我的另一个问题here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-23
  • 2014-01-19
  • 1970-01-01
  • 1970-01-01
  • 2013-11-26
相关资源
最近更新 更多