我将这个答案分成多个部分。
ARB_separate_shader_objects 的目的是什么
此功能的目的是能够轻松地在顶点/片段/几何/镶嵌着色器之间进行混合和匹配。
目前,您必须将所有着色器阶段链接到一个整体程序中。所以我可以使用相同的顶点着色器代码和两个不同的片段着色器。但这会导致两个不同的程序。
每个程序都有自己的一套制服和其他状态。这意味着如果我想更改顶点着色器中的一些统一数据,我必须在两个程序中都进行更改。我必须glGetUniformLocation
在每个上使用(因为它们可能有不同的位置)。然后我必须单独设置每个值。
这是一个很大的痛苦,而且是非常不必要的。使用单独的着色器,您不必这样做。您有一个仅包含顶点着色器的程序,以及两个包含两个片段着色器的程序。更改顶点着色器制服不需要两次glGetUniformLocation
调用。事实上,缓存数据更容易,因为只有一个顶点着色器。
此外,它还处理着色器组合的组合爆炸。
假设您有一个执行简单刚性转换的顶点着色器:它需要一个模型到相机矩阵和一个相机到剪辑矩阵。也可能是法线矩阵。你有一个片段着色器,它将从一些纹理中采样,基于法线进行一些光照计算,并返回一个颜色。
现在假设您添加了另一个片段着色器,它采用额外的光照和材质参数。它没有来自顶点着色器的任何新输入(没有新的纹理坐标或任何东西),只有新的制服。也许它用于投影照明,顶点着色器不参与其中。任何。
现在假设我们添加了一个执行顶点加权蒙皮的新顶点着色器。它提供与旧的顶点着色器相同的输出,但它有一堆用于蒙皮的制服和输入权重。
这给了我们 2 个顶点着色器和 2 个片段着色器。一共4个程序组合。
当我们添加 2 个以上兼容的片段着色器时会发生什么?我们得到 8 种组合。如果我们有 3 个顶点着色器和 10 个片段着色器,我们总共有30个程序组合。
使用单独的着色器,3 个顶点着色器和 10 个片段着色器需要 30 个程序管道对象,但只有13 个程序对象。这比非独立案例少 50% 以上的程序对象。
为什么引用的文字是错误的
现在,这条线 [...] 让我想知道。
它应该让你想知道;它在几个方面是错误的。例如:
VAO 是一个容器对象,它链接缓冲区数据、顶点布局数据和 GLSL 程序输入数据。
不,不是的。它将提供顶点数据的缓冲区对象与该数据的顶点格式联系起来。它指定了哪些顶点属性索引。但这与“GLSL 程序输入数据”的耦合程度如何完全取决于您。
如果没有专门的软件设计,这意味着当我改变一个对象的材质(一个新的片段着色器)时,我需要不同的 VAO...
除非这条线将“专门的软件设计”等同于“合理的编程实践”,否则这纯粹是胡说八道。
这就是我的意思。当他们设置顶点数据时,您会在网上看到这样的示例代码:
glBindBuffer(GL_ARRAY_BUFFER, buffer_object);
glEnableVertexAttribArray(glGetAttribLocation(prog, "position"));
glVertexAttribPointer(glGetAttribLocation(prog, "position"), ...);
对此有一个技术术语:糟糕的代码。这样做的唯一原因是如果 指定的着色器prog
不在您的直接控制之下。如果是这样的话......你怎么知道它prog
有一个名为“位置”的属性?
着色器的合理编程实践是使用约定。这就是您知道prog
有一个名为“位置”的属性的方式。但是如果你知道每个程序都会有一个名为“位置”的属性,为什么不更进一步呢?当需要链接程序时,请执行以下操作:
GLuint prog = glCreateProgram();
glAttachShader(prog, ...); //Repeat as needed.
glBindAttribLocation(prog, 0, "position");
毕竟,你知道这个程序必须有一个名为“位置”的属性;您将假设稍后获得它的位置。所以去掉中间人,告诉 OpenGL使用什么位置。
这样,您不必使用glGetAttribLocation
; 当您的意思是“位置”时,只需使用 0。
即使prog
没有名为“位置”的属性,这仍然会成功链接。如果您绑定不存在的属性位置,OpenGL 不介意。因此,您可以对您创建的每个程序应用一系列glBindAttribLocation
调用,而不会出现问题。实际上,您可以对属性名称有多种约定,只要您坚持一组或另一组,就可以了。
更好的是,将其粘贴在着色器中,并且根本不用理会glBindAttribLocation
解决方案:
#version 330
layout(location = 0) in vec4 position;
简而言之:始终为您的属性位置使用约定。如果您glGetAttribLocation
在程序中看到,请考虑代码异味。这样,您可以将任何 VAO 用于任何程序,因为 VAO 只是违反约定编写的。
我不明白约定如何等同于“专用软件设计”,但是,嘿,我也没有写那行。