我一直在阅读这个 OpenGL4.1新功能评论.我真的不明白GL_ARB_separate_program_objects使用背后的想法,至少基于帖子作者的说法:
它允许独立使用着色器阶段而无需更改其他着色器阶段.我看到两个主要原因:Direct3D,Cg甚至旧的OpenGL ARB程序都能做到这一点,但更重要的是它带来了一些软件设计灵活性,允许以更低的粒度查看图形管道.例如,我最好的敌人VAO是一个容器对象,它链接缓冲区数据,顶点布局数据和GLSL程序输入数据.如果没有专门的软件设计,这意味着当我更改对象的材质(一个新的片段着色器)时,我需要不同的VAO ...幸运的是,可以保留相同的VAO,并且只能通过定义如何更改程序在C++程序和GLSL程序之间进行通信.即使存在一些缺点,它也能很好地工作.
现在,这一行:
例如,我最好的敌人VAO是一个容器对象,它链接缓冲区数据,顶点布局数据和GLSL程序输入数据.没有专用的软件设计,这意味着当我更改对象的材质(一个新的片段着色器) ,我需要不同的VAO ......
令我惊讶.在我的OpenGL程序中,我使用VAO对象,我可以在不同的着色器程序之间切换而不对VAO本身做任何改动.所以,我是否误解了整个想法?也许他意味着我们可以在不重新链接的情况下为同一个程序切换着色器?
Nic*_*las 10
我把这个答案分成了几个部分.
此功能的目的是能够轻松地在顶点/片段/几何/曲面细分着色器之间进行混合和匹配.
目前,您必须将所有着色器阶段链接到一个单片程序中.所以我可以使用相同的顶点着色器代码和两个不同的片段着色器.但这导致了两个不同的程序.
每个程序都有自己的一套制服和其他状态.这意味着如果我想在顶点着色器中更改一些统一数据,我必须在两个程序中更改它.我必须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"), ...);
Run Code Online (Sandbox Code Playgroud)
对此有一个技术术语:可怕的代码.这样做的唯一原因是如果指定的着色器prog在某种程度上不在您的直接控制之下.如果是这样的话......你怎么知道它prog有一个名为"位置"的属性?
着色器的合理编程实践是使用约定.这就是你知道如何知道prog一个名为"position"的属性.但是如果你知道每个程序都有一个名为"position"的属性,为什么不进一步呢?在链接程序时,请执行以下操作:
GLuint prog = glCreateProgram();
glAttachShader(prog, ...); //Repeat as needed.
glBindAttribLocation(prog, 0, "position");
Run Code Online (Sandbox Code Playgroud)
毕竟,你知道这个程序必须有一个名为"position"的属性; 当你稍后得到它的位置时,你会假设它.因此,切断中间人并告诉OpenGL使用什么位置.
这样,您就不必使用glGetAttribLocation; 当你的意思是"位置"时,只需使用0.
即使prog没有名为"position"的属性,这仍然会成功链接.如果绑定不存在的属性位置,OpenGL不介意.因此,您可以glBindAttribLocation对您创建的每个程序应用一系列调用,而不会出现任何问题.实际上,您可以为属性名称设置多个约定,只要您坚持使用一组或另一组,就可以了.
更好的是,将其粘贴在着色器中并且根本不需要glBindAttribLocation解决方案:
#version 330
layout(location = 0) in vec4 position;
Run Code Online (Sandbox Code Playgroud)
简而言之:始终对属性位置使用约定.如果您glGetAttribLocation在程序中看到,请考虑代码味道.这样,您可以将任何VAO用于任何程序,因为VAO只是根据惯例编写的.
我没有看到约会如何等同于"专用软件设计",但是嘿,我也没有写过那条线.
我可以在不同的着色器程序之间切换
是的,但您必须完全替换整个程序。单独的着色器对象允许您仅替换一个阶段(例如,仅顶点着色器)。
例如,如果您有 N 个顶点着色器和 M 个顶点着色器,使用常规链接您将拥有 N * M 个程序对象(以涵盖所有可能的组合)。使用单独的着色器对象,它们彼此分离,因此您只需要保留 N + M 个着色器对象。这是在复杂场景中的显着改进。
| 归档时间: |
|
| 查看次数: |
1439 次 |
| 最近记录: |