opengl - OpenGL 4.1 GL_ARB_separate_program_objects的用途

标签 opengl

我一直在阅读this OpenGL4.1新功能评论。我真的不理解GL_ARB_separate_program_objects用法背后的想法,至少基于帖子作者的说法:


它允许独立使用着色器阶段,而无需更改其他阶段
着色器阶段。我看到了两个主要原因:Direct3D,Cg甚至
旧的OpenGL ARB程序可以做到,但更重要的是它带来了一些
软件设计灵活性允许查看图形管线
较低的粒度。例如,我最好的敌人VAO是
链接缓冲区数据,顶点布局数据和GLSL的容器对象
程序输入数据。没有专用的软件设计,这意味着
当我更改对象的材质(新的片段着色器)时,
我需要不同的VAO ...很幸运,可以保持相同的VAO
并且仅通过定义有关如何
在C ++程序和GLSL程序之间进行通信。有用
即使有些弊端仍然存在。


现在,这一行:

例如,我最大的敌人VAO是一个链接缓冲区数据,顶点布局数据和GLSL程序输入数据的容器对象,而没有专用的软件设计,这意味着当我更改对象的材质时(新的片段着色器) ,我需要不同的VAO ...

让我感到奇怪。在我的OpenGL程序中,我使用VAO对象,并且可以在不同的着色器程序之间进行切换,而无需对VAO本身进行任何更改。因此,我是否误解了整个想法?也许他是说我们可以为同一程序切换着色器而无需重新链接?

最佳答案

我将这个答案分为多个部分。

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根本没有一个名为“ position”的属性?

着色器的合理编程做法是使用约定。这就是您知道prog具有名为“ position”的属性的方式。但是,如果您知道每个程序都将具有一个名为“ position”的属性,那为什么不更进一步呢?当需要链接程序时,请执行以下操作:

GLuint prog = glCreateProgram();
glAttachShader(prog, ...); //Repeat as needed.
glBindAttribLocation(prog, 0, "position");


毕竟,您知道该程序必须具有一个名为“ position”的属性。您将假设以后获得它的位置。因此,请切掉中间人,并告诉OpenGL使用哪个位置。

这样,您就不必使用glGetAttribLocation了。表示“位置”时只需使用0。

即使prog没有名为“ position”的属性,这仍将成功链接。 OpenGL不在乎是否绑定不存在的属性位置。因此,您可以将一系列glBindAttribLocation调用应用于您创建的每个程序,而不会出现问题。实际上,属性名称可以有多种约定,只要坚持使用一套或另一套,就可以了。

更好的是,将其粘贴在着色器中,根本不用理会glBindAttribLocation解决方案:

#version 330
layout(location = 0) in vec4 position;


简而言之:始终对属性位置使用约定。如果您在程序中看到glGetAttribLocation,请认为该代码有气味。这样,您可以对任何程序使用任何VAO,因为VAO只是根据约定编写的。

我没有看到约定如何等同于“专用软件设计”,但是,我也没有写这条线。

关于opengl - OpenGL 4.1 GL_ARB_separate_program_objects的用途,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15809888/

相关文章:

c++ - 全高清 2D 纹理内存 OpenGL

c++ - 当提供轴和四元数时,如何使用 GLM 获得角度?

opengl - glGenTextures - 纹理数量有限制吗?

c++ - 如何使键盘输入的 Action 即时

c++ - Opengl版本问题 glew.h

opengl - 如何使用 glDrawElements 对 tex 坐标数组和顶点数组使用不同的索引

无法在 OpenGL 中绘制三角形

c++ - 链接 GLEW 和其他人,_glViewport 是唯一 Unresolved

c++ - 替代过剩

OpenGL:如何在 glVertex3i 中使用整数