所以我只是在学习几何着色器,我有一个用例。
出于性能原因,我不想一直使用几何着色器,即使作为 channel ,因为大多数对象大部分时间都不需要它。但是,当我确实想要它时,顶点和片段着色器应该做同样的事情。我可以重复使用我的顶点和片段着色器吗?
IE。
顶点:
#version 330
in vec3 position;
out vec3 whatever;
void main()
{
...
}
几何:
#version 330
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
in whatever[];
out whatever;
void main()
{
...
}
片段:
#version 330
in whatever
void main()
{
...
}
因此,如果没有几何着色器,它就可以工作,因为顶点 outwhat
对应于片段 inwhat
。然而,使用几何着色器,我最终将任何东西重新定义为输入和输出。
我读到你可以使用:layout (location = 0) out whatever
然后你不需要相同的名称,但这对我不起作用,给出编译错误:错误:-1:65535:'':存储限定符与布局限定符 id 无效
。我认为这是因为我没有足够新的 opengl 版本来支持该语法。
我还读到您可以使用扩展名:arb_separate_shader_objects,但未能找到任何使用它的示例。
有什么建议吗?
最佳答案
您实际上可以做到这一点。但是你需要interface blocks去做吧。事实上,这是创建输入/输出接口(interface) block 来解决的主要问题之一:
#version 330
in vec3 position;
out Data
{
vec3 whatever;
};
void main()
{
...
whatever = ...;
}
这是您的顶点着色器,使用接口(interface) block 作为其输出。顶点着色器输入不能聚合到接口(interface) block 中。请注意,顶点着色器调用接口(interface) block 的成员whatever
。这很快就会很重要。
在您的片段着色器中:
#version 330
in Data
{
in vec3 whatever;
};
void main()
{
...
... = whatever;
}
片段着色器现在声明了一个补充输入 block 。为了使其工作,该 block 必须使用与前一阶段的相应输出 block 相同的名称。并且它必须以相同的顺序声明所有个与对应的输出 block 相同的变量。
再次注意,片段着色器将变量称为whatever
。目前这很重要。
如果您使用这两个着色器并将它们链接在一起(直接或间接使用 separate programs),它们会正常工作。现在,是时候看看几何着色器在它们之间应该是什么样子了:
#version 330
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
in Data
{
vec3 whatever;
} vertex_input[];
out Data
{
vec3 whatever;
} vertex_output;
void main()
{
...
vertex_output.whatever = vertex_input[0].whatever;
}
好的,刚刚发生了很多的事情。
首先你会注意到,我们似乎已经两次声明了同一个接口(interface) block 。不,我们没有;输入和输出接口(interface) block 位于不同的命名空间中。所以声明一个与输出同名的输入接口(interface) block 是完全可以的。
输入 Data
与来自顶点着色器的输出 Data
匹配。输出 Data
与片段着色器的输入 Data
匹配。所以接口(interface)匹配。
现在,您可能会注意到我们声明这些 block 的方式不同。输入 block 有一个标签vertex_input[]
,而输出 block 有一个vertex_output
。这不像在 C/C++ 中的结构声明之后声明的结构变量。这个名字就是所谓的接口(interface) block 的instance name。 .这很重要。
为什么?因为它允许我们限定接口(interface) block 成员的名称。
没有实例名称的 block 声明其成员的全局范围。这就是为什么我们可以在 VS 和 FS 中仅使用该名称来引用 whatever
。然而,由于 GS 需要有两个独立的 whatever
变量,我们需要一些方法来区分它们。
这就是实例名称的用途。通过给 block 一个实例名称,我们必须在所有对该变量的引用前加上该实例名称。
请注意,跨接口(interface)的 block 由 block 名称匹配。也就是说,GS 的输入与 VS 的输出相匹配,因为它们都被命名为 Data
。实例名称仅在着色器中用于命名范围成员。不影响接口(interface)匹配。
最后,您会注意到 GS 的输入变量不是数组。相反,它是排列的接口(interface) block 的实例名称。这就是接口(interface) block 在 GS 中的工作方式(以及采用阵列输入/输出的曲面分割着色器)。
鉴于此定义,您可以在 VS 和 FS 之间滑动此 GS,而无需更改其中任何一个。所以你根本不需要修改 VS 或 FS 代码(显然除了使用接口(interface) block 之外)。
关于opengl - 是否可以有相同的顶点着色器和片段着色器,有或没有几何着色器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34816821/