是否可以使用具有或不具有几何着色器的相同顶点着色器和片段着色器?

时间:2016-01-15 17:43:23

标签: opengl glsl shader geometry-shader

所以我只是学习几何着色器,我有一个用例。

出于性能原因,我不想一直使用几何着色器,即使是通过,因为大多数时候大多数对象都不需要它。但是当我想要它时,顶点和片段着色器应该做同样的事情。我可以重用我的顶点和片段着色器。

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()
{
    ...
}

因此,如果没有几何着色器,则顶点out whatever对应于片段in whatever。然而,使用几何着色器,我最终会重新加工任何内部和外部。

我知道您可以使用:layout (location = 0) out whatever然后您不需要相同的名称,但这对我没有用,给出了编译错误:ERROR: -1:65535: '' : storage qualifier not valid with layout qualifier id。我认为这是因为我没有足够新的opengl版本来支持这种语法。

我还读到你可以使用扩展名:arb_separate_shader_objects,但未找到任何使用它的例子。

有什么建议吗?

1 个答案:

答案 0 :(得分:4)

事实上你可以做到这一点。但是你需要interface blocks才能做到这一点。实际上,这是创建输入/输出接口块以解决的主要问题之一:

#version 330
in vec3 position;
out Data
{
  vec3 whatever;
};

void main()
{
    ...
    whatever = ...;
}

这是您的顶点着色器,使用接口块作为其输出。顶点着色器输入无法聚合到接口块中。请注意,顶点着色器调用接口块whatever的成员。这很快就会很重要。

在片段着色器中:

#version 330
in Data
{
    in vec3 whatever;
};

void main()
{
    ...
    ... = whatever;
}

片段着色器现在声明了一个补充输入块。为了使其工作,块必须使用与前一阶段的相应输出块相同的名称。它必须以相同的顺序声明与相应输出块相同的变量的所有

再次注意片段着色器将变量称为whatever。这在目前很重要。

如果您使用这两个着色器并将它们链接在一起(直接或间接与separate programs),它们将正常工作。现在,是时候看看Geometry Shader在它们之间看起来是什么样的了:

#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;
}

好的,发生了很多的事情。

您要注意的第一件事是我们似乎已经两次声明了相同的接口块。不,我们没有;输入和输出接口块位于不同的命名空间中。因此,声明一个具有相同块名称的输入接口块作为输出接口块是完全正确的。

输入Data与顶点着色器的输出Data匹配。输出Data与片段着色器的输入Data匹配。所以接口匹配。

现在,您可能会注意到我们以不同方式声明了这些块。输入块具有标记vertex_input[],而输出块具有vertex_output。这不像在C / C ++中的结构声明之后声明的结构变量。这个名称就是所谓的接口块instance name。这非常重要。

为什么呢?因为它允许我们对接口块成员的名称进行范围化。

在没有实例名称的情况下声明的块全局范围成员。这就是为什么我们可以使用该名称引用VS和FS中的whatever。但是,由于GS需要有两个单独的whatever变量,我们需要一些方法来区分它们。

这是实例名称的用途。通过为块提供实例名称,我们必须在该变量的所有引用前加上该实例名称。

请注意,跨接口的块由块名称匹配。也就是说,GS的输入与VS的输出匹配,因为它们都被命名为Data。实例名称仅 在着色器中用于名称范围成员。它不会影响接口匹配。

最后,您会注意到GS的输入变量不是数组。它取而代之的是排列的接口块的实例名称。这就是接口块如何在GS(以及采用阵列输入/输出的曲面细分着色器)中工作的方式。

根据这个定义,你可以在VS和FS之间放置这个GS,而不必改变它们中的任何一个。因此,您根本不必修改VS或FS代码(显然除了使用接口块之外)。