And*_*ane 3 opengl shader glsl geometry-shader
所以我只是在学习几何着色器,我有一个用例。
出于性能方面的考虑,我不想一直使用几何着色器,甚至也不想使用它,因为大多数时候大多数对象都不需要它。但是,当我确实需要它时,顶点着色器和片段着色器应该做同样的事情。我可以重用顶点和片段着色器吗?
IE浏览器
顶点:
#version 330
in vec3 position;
out vec3 whatever;
void main()
{
...
}
Run Code Online (Sandbox Code Playgroud)
几何:
#version 330
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
in whatever[];
out whatever;
void main()
{
...
}
Run Code Online (Sandbox Code Playgroud)
分段:
#version 330
in whatever
void main()
{
...
}
Run Code Online (Sandbox Code Playgroud)
因此,在没有几何着色器的情况下,这是可行的,因为顶点out whatever对应于fragment in whatever。但是,使用几何体着色器,我最终要重新定义输入和输出。
我读到可以使用:layout (location = 0) out whatever,然后不需要相同的名称,但这对我不起作用,出现编译错误:ERROR: -1:65535: '' : storage qualifier not valid with layout qualifier id。我认为这是由于我没有足够新的opengl版本来支持该语法。
我也读过您可以使用扩展名:arb_separate_shader_objects,但是找不到使用它的任何示例。
有什么建议么?
实际上,您可以这样做。但是,您需要接口块来执行此操作。实际上,这是创建输入/输出接口块以解决的主要问题之一:
#version 330
in vec3 position;
out Data
{
vec3 whatever;
};
void main()
{
...
whatever = ...;
}
Run Code Online (Sandbox Code Playgroud)
这是您的顶点着色器,使用接口块作为其输出。顶点着色器输入不能聚合到接口块中。请注意,顶点着色器调用接口块的成员whatever。这很快将很重要。
在片段着色器中:
#version 330
in Data
{
in vec3 whatever;
};
void main()
{
...
... = whatever;
}
Run Code Online (Sandbox Code Playgroud)
现在,片段着色器声明了一个补充输入块。为了使它起作用,该块必须使用与上一级对应的输出块相同的名称。并且必须以相同的顺序声明所有与相同的输出块相同的变量。
再次注意,片段着色器将变量称为whatever。目前这很重要。
如果您使用了这两个着色器并将它们链接在一起(直接或间接使用单独的程序),则它们会正常工作。现在,是时候看看“几何着色器”在它们之间必须看起来像什么了:
#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;
}
Run Code Online (Sandbox Code Playgroud)
好,发生了很多事情。
您要注意的第一件事是,我们似乎已经两次声明了相同的接口块。不,我们没有;输入和输出接口块位于不同的名称空间中。因此,最好将一个输入接口块声明为与输出接口块相同的名字。
输入Data与Data顶点着色器的输出匹配。输出Data与Data片段着色器的输入匹配。因此接口匹配。
现在,您可能会注意到我们对这些块的声明有所不同。输入块具有标签vertex_input[],而输出块具有vertex_output。这不像在C / C ++中的struct声明之后声明的struct变量。该名称是所谓的接口块的实例名称。这个非常重要。
为什么?因为它允许我们限定接口块成员的名称。
没有实例名称声明的块将全局范围内的成员。这就是为什么我们可以whatever在VS和FS中仅使用该名称进行引用的原因。但是,由于GS需要具有两个单独的whatever变量,因此我们需要某种方法来区分它们。
这就是实例名称的用途。通过为该块指定实例名称,我们必须以该实例名称为对该变量的所有引用添加前缀。
注意,跨接口的块由块名匹配。也就是说,GS的输入与VS的输出匹配,因为它们都被命名为Data。实例名称仅在着色器中用于名称作用域成员。它不影响接口匹配。
最后,您会注意到GS的输入变量不是数组。而是排列的接口块的实例名称。这就是接口块在GS(以及采用阵列输入/输出的镶嵌着色器)中工作的方式。
有了这个定义,您可以在VS和FS之间滑动此GS,而无需更改它们中的任何一个。因此,您根本不需要修改VS或FS代码(显然除了使用接口块之外)。
| 归档时间: |
|
| 查看次数: |
1315 次 |
| 最近记录: |