顶点着色器如何访问与另一个 shaderprogram 属性绑定的顶点缓冲区数据?
How the vertex shader access the vertex buffer data bound with another shaderprogram attribute?
我创建了两个着色器程序 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 生成的输出!:
代码经过简化,使用 Qt Creator 编写 Windows:
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);
编辑后的代码输出为:
这里出现一个问题,如果两个程序都为唯一的属性使用相同的位置,那么它们应该生成一个或另一个三角形,而不是都由于覆盖!?
请耐心等待,我才刚刚开始学习。
Isn't it strange that the vertex shader of shaderProgram1 access the buffer data which is bound with shaderProgram0 attribute?
没有
如果您没有在着色器中明确指定属性位置,或者在链接程序之前使用 glBindAttribLocation
,则该实现将为您任意分配顶点属性位置。不要求单独的程序使用单独的属性位置。事实上,通常建议您尽可能使您的属性位置接口在程序之间兼容。
在您的情况下,实施恰好将它们分配到同一位置。因此,任一 VAO 都可以与任一程序一起使用。
我创建了两个着色器程序 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 生成的输出!:
代码经过简化,使用 Qt Creator 编写 Windows:
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);
编辑后的代码输出为:
这里出现一个问题,如果两个程序都为唯一的属性使用相同的位置,那么它们应该生成一个或另一个三角形,而不是都由于覆盖!? 请耐心等待,我才刚刚开始学习。
Isn't it strange that the vertex shader of shaderProgram1 access the buffer data which is bound with shaderProgram0 attribute?
没有
如果您没有在着色器中明确指定属性位置,或者在链接程序之前使用 glBindAttribLocation
,则该实现将为您任意分配顶点属性位置。不要求单独的程序使用单独的属性位置。事实上,通常建议您尽可能使您的属性位置接口在程序之间兼容。
在您的情况下,实施恰好将它们分配到同一位置。因此,任一 VAO 都可以与任一程序一起使用。