opengl - 是否可以有相同的顶点着色器和片段着色器,有或没有几何着色器?

标签 opengl glsl shader geometry-shader

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

出于性能原因,我不想一直使用几何着色器,即使作为 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/

相关文章:

opengl - OpenGL 中的深度偏移

java - 当我尝试使用着色器时,OpenGL 向我发送堆栈下溢错误 (Java)

c - 简单的平面 segmentation 着色器

java - 如何在 jogl 中使用 gluPerspective()?

opengl - 使用没有纹理的 glsl 将发光效果应用于正方形

glsl - WebGL 使用什么版本的 GLSL

c++ - 从 opengl 中的模型获取可见的 XYZ 坐标和法线

c++ - 如何在现代 Opengl 中添加 View 矩阵

c++ - OpenGL 围绕点移动相机

c++ - glDrawArraysInstanced 没有在 OpenGL 中进行多次绘制调用?